33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 *--------------------------------------------------------------------------------------------*/
55
6+ import { isString } from 'vs/base/common/types' ;
7+
68/**
79 * Return a hash value for an object.
810 */
@@ -69,4 +71,345 @@ export class Hasher {
6971 this . _value = hash ( obj , this . _value ) ;
7072 return this . _value ;
7173 }
72- }
74+ }
75+
76+ //#region SHA1
77+
78+ export function computeSHA1Hash ( value : string ) : string {
79+ const data = encodeToArrayBuffer ( value ) ;
80+ const hash = new SHA1 ( ) ;
81+
82+ if ( data . byteLength ) {
83+ hash . update ( data ) ;
84+ }
85+
86+ return hash . digest ( ) ;
87+ }
88+
89+ class SHA1 {
90+
91+ // Reference: http://en.wikipedia.org/wiki/SHA-1
92+
93+ private static BLOCK_SIZE = 64 ; // 512 / 8
94+
95+ private length : number ;
96+ private buffer : Uint8Array | null ;
97+ private bufferDV : DataView | null ;
98+ private bufferLength : number ;
99+
100+ private bigBlock32 : DataView ;
101+ private h0 = 0x67452301 ;
102+ private h1 = 0xEFCDAB89 ;
103+ private h2 = 0x98BADCFE ;
104+ private h3 = 0x10325476 ;
105+ private h4 = 0xC3D2E1F0 ;
106+
107+ static digest ( data : string ) : string ;
108+ static digest ( data : Uint8Array ) : string ;
109+ static digest ( data : ArrayBuffer ) : string ;
110+ static digest ( data : DataView ) : string ;
111+ static digest ( data : any ) : string {
112+ let sha = new SHA1 ( ) ;
113+ sha . update ( data ) ;
114+
115+ return sha . digest ( ) ;
116+ }
117+
118+ constructor ( ) {
119+ this . length = 0 ;
120+
121+ this . buffer = new Uint8Array ( SHA1 . BLOCK_SIZE ) ;
122+ this . bufferDV = new DataView ( this . buffer . buffer ) ;
123+ this . bufferLength = 0 ;
124+
125+ this . bigBlock32 = new DataView ( new ArrayBuffer ( 320 ) ) ; // 80 * 4 = 320;
126+ }
127+
128+ update ( data : string ) : void ;
129+ update ( data : Uint8Array ) : void ;
130+ update ( data : ArrayBuffer ) : void ;
131+ update ( data : DataView ) : void ;
132+ update ( arg : any ) : void {
133+ if ( ! this . buffer || ! this . bufferDV ) {
134+ throw new Error ( 'Digest already computed.' ) ;
135+ }
136+
137+ let data : Uint8Array ;
138+
139+ if ( isString ( arg ) ) {
140+ data = new Uint8Array ( encodeToArrayBuffer ( < string > arg ) ) ;
141+ } else if ( arg instanceof ArrayBuffer ) {
142+ data = new Uint8Array ( arg ) ;
143+ } else if ( arg instanceof DataView ) {
144+ data = new Uint8Array ( ( < DataView > arg ) . buffer ) ;
145+ } else {
146+ data = < Uint8Array > arg ;
147+ }
148+
149+ let bytesRead = 0 , totalBytesRead = 0 ;
150+
151+ while ( totalBytesRead < data . byteLength ) {
152+ bytesRead = copy ( this . buffer , this . bufferLength , data , totalBytesRead , data . byteLength ) ;
153+
154+ this . bufferLength += bytesRead ;
155+ totalBytesRead += bytesRead ;
156+
157+ if ( this . bufferLength === SHA1 . BLOCK_SIZE ) {
158+ this . step ( this . bufferDV ) ;
159+ this . bufferLength = 0 ;
160+ }
161+ }
162+
163+ this . length += totalBytesRead ;
164+ }
165+
166+ digest ( ) : string {
167+ if ( this . buffer ) {
168+ this . wrapUp ( ) ;
169+ }
170+
171+ return toHexString ( this . h0 ) + toHexString ( this . h1 ) + toHexString ( this . h2 ) + toHexString ( this . h3 ) + toHexString ( this . h4 ) ;
172+ }
173+
174+ private wrapUp ( ) : void {
175+ if ( ! this . buffer || ! this . bufferDV ) {
176+ return ; // already wrapped up
177+ }
178+
179+ this . buffer [ this . bufferLength ++ ] = 0x80 ;
180+ fill ( this . buffer , this . bufferLength ) ;
181+
182+ if ( this . bufferLength > 56 ) {
183+ this . step ( this . bufferDV ) ;
184+ fill ( this . buffer ) ;
185+ }
186+
187+ let ml = multiply64 ( 8 , this . length ) ;
188+ this . bufferDV . setUint32 ( 56 , ml [ 0 ] , false ) ;
189+ this . bufferDV . setUint32 ( 60 , ml [ 1 ] , false ) ;
190+
191+ this . step ( this . bufferDV ) ;
192+
193+ this . buffer = null ;
194+ this . bufferDV = null ;
195+ this . bufferLength = - 1 ;
196+ }
197+
198+ private step ( data : DataView ) : void {
199+ for ( let j = 0 ; j < 64 /* 16*4 */ ; j += 4 ) {
200+ this . bigBlock32 . setUint32 ( j , data . getUint32 ( j , false ) , false ) ;
201+ }
202+
203+ for ( let j = 64 ; j < 320 /* 80*4 */ ; j += 4 ) {
204+ this . bigBlock32 . setUint32 ( j , leftRotate ( ( this . bigBlock32 . getUint32 ( j - 12 , false ) ^ this . bigBlock32 . getUint32 ( j - 32 , false ) ^ this . bigBlock32 . getUint32 ( j - 56 , false ) ^ this . bigBlock32 . getUint32 ( j - 64 , false ) ) , 1 ) , false ) ;
205+ }
206+
207+ let a = this . h0 ;
208+ let b = this . h1 ;
209+ let c = this . h2 ;
210+ let d = this . h3 ;
211+ let e = this . h4 ;
212+
213+ let f : number , k : number ;
214+ let temp : number ;
215+
216+ for ( let j = 0 ; j < 80 ; j ++ ) {
217+ if ( j < 20 ) {
218+ f = ( b & c ) | ( ( ~ b ) & d ) ;
219+ k = 0x5A827999 ;
220+ } else if ( j < 40 ) {
221+ f = b ^ c ^ d ;
222+ k = 0x6ED9EBA1 ;
223+ } else if ( j < 60 ) {
224+ f = ( b & c ) | ( b & d ) | ( c & d ) ;
225+ k = 0x8F1BBCDC ;
226+ } else {
227+ f = b ^ c ^ d ;
228+ k = 0xCA62C1D6 ;
229+ }
230+
231+ temp = ( leftRotate ( a , 5 ) + f + e + k + this . bigBlock32 . getUint32 ( j * 4 , false ) ) & 0xFFFFFFFF ;
232+ e = d ;
233+ d = c ;
234+ c = leftRotate ( b , 30 ) ;
235+ b = a ;
236+ a = temp ;
237+ }
238+
239+ this . h0 = ( this . h0 + a ) & 0xFFFFFFFF ;
240+ this . h1 = ( this . h1 + b ) & 0xFFFFFFFF ;
241+ this . h2 = ( this . h2 + c ) & 0xFFFFFFFF ;
242+ this . h3 = ( this . h3 + d ) & 0xFFFFFFFF ;
243+ this . h4 = ( this . h4 + e ) & 0xFFFFFFFF ;
244+ }
245+ }
246+
247+ function leftPad ( value : string , length : number , char : string = '0' ) : string {
248+ return new Array ( length - value . length + 1 ) . join ( char ) + value ;
249+ }
250+
251+ function toHexString ( value : number , bitsize : number = 32 ) : string {
252+ return leftPad ( ( value >>> 0 ) . toString ( 16 ) , bitsize / 4 ) ;
253+ }
254+
255+ function leftRotate ( value : number , bits : number , totalBits : number = 32 ) : number {
256+
257+ // delta + bits = totalBits
258+ let delta = totalBits - bits ;
259+
260+ // All ones, expect `delta` zeros aligned to the right
261+ let mask = ~ ( ( 1 << delta ) - 1 ) ;
262+
263+ // Join (value left-shifted `bits` bits) with (masked value right-shifted `delta` bits)
264+ return ( ( value << bits ) | ( ( mask & value ) >>> delta ) ) >>> 0 ;
265+ }
266+
267+ function multiply64 ( a : number , b : number ) : number [ ] {
268+ /* A1 A0 => A
269+ * B1 B0 => B
270+ * B0 * A1 B0 * A0
271+ * B1 * A1 B1 * A0
272+ * C3 C2 C1 C0 => C
273+ */
274+
275+ let a0 = a & 0xFFFF , a1 = a >>> 16 ;
276+ let b0 = b & 0xFFFF , b1 = b >>> 16 ;
277+ let c0 = 0 , c1 = 0 , c2 = 0 , c3 = 0 ;
278+
279+ let x = b0 * a0 ;
280+ c0 += x & 0xFFFF ;
281+ c1 += x >>> 16 ;
282+
283+ x = b0 * a1 ;
284+ c1 += x & 0xFFFF ;
285+ c2 += x >>> 16 ;
286+
287+ x = b1 * a0 ;
288+ c1 += x & 0xFFFF ;
289+ c2 += x >>> 16 ;
290+
291+ c2 += c1 >>> 16 ;
292+ c1 = c1 & 0xFFFF ;
293+
294+ x = b1 * a1 ;
295+ c2 += x & 0xFFFF ;
296+ c3 += x >>> 16 ;
297+
298+ c3 += c2 >>> 16 ;
299+ c2 = c2 & 0xFFFF ;
300+
301+ return [ ( c3 << 16 | c2 ) >>> 0 , ( c1 << 16 | c0 ) >>> 0 ] ;
302+ }
303+
304+ function encodeToArrayBuffer ( str : string ) : ArrayBuffer {
305+ let i : number , len : number , length = 0 , charCode = 0 , trailCharCode = 0 , codepoint = 0 ;
306+
307+ // First pass, for the size
308+ for ( i = 0 , len = str . length ; i < len ; i ++ ) {
309+ charCode = str . charCodeAt ( i ) ;
310+
311+ // Surrogate pair
312+ if ( charCode >= 0xD800 && charCode < 0xDC00 ) {
313+ trailCharCode = str . charCodeAt ( ++ i ) ;
314+
315+ if ( ! ( trailCharCode >= 0xDC00 && trailCharCode < 0xE000 ) ) {
316+ throw new Error ( 'Invalid char code' ) ;
317+ }
318+
319+ // Code point can be obtained by subtracting 0xD800 and 0xDC00 from both char codes respectively
320+ // and joining the 10 least significant bits from each, finally adding 0x10000.
321+ codepoint = ( ( ( ( charCode - 0xD800 ) & 0x3FF ) << 10 ) | ( ( trailCharCode - 0xDC00 ) & 0x3FF ) ) + 0x10000 ;
322+
323+ } else {
324+ codepoint = charCode ;
325+ }
326+
327+ length += byteSizeInUTF8 ( codepoint ) ;
328+ }
329+
330+ let result = new ArrayBuffer ( length ) ;
331+ let view = new Uint8Array ( result ) ;
332+ let pos = 0 ;
333+
334+ // Second pass, for the data
335+ for ( i = 0 , len = str . length ; i < len ; i ++ ) {
336+ charCode = str . charCodeAt ( i ) ;
337+
338+ if ( charCode >= 0xD800 && charCode < 0xDC00 ) {
339+ trailCharCode = str . charCodeAt ( ++ i ) ;
340+ codepoint = ( ( ( ( charCode - 0xD800 ) & 0x3FF ) << 10 ) | ( ( trailCharCode - 0xDC00 ) & 0x3FF ) ) + 0x10000 ;
341+ } else {
342+ codepoint = charCode ;
343+ }
344+
345+ pos += writeUTF8 ( codepoint , view , pos ) ;
346+ }
347+
348+ return result ;
349+ }
350+
351+ function byteSizeInUTF8 ( codePoint : number ) : number {
352+ codePoint = codePoint >>> 0 ;
353+
354+ if ( codePoint < 0x80 ) {
355+ return 1 ;
356+ } else if ( codePoint < 0x800 ) {
357+ return 2 ;
358+ } else if ( codePoint < 0x10000 ) {
359+ return 3 ;
360+ } else if ( codePoint < 0x200000 ) {
361+ return 4 ;
362+ } else if ( codePoint < 0x4000000 ) {
363+ return 5 ;
364+ } else if ( codePoint < 0x80000000 ) {
365+ return 6 ;
366+ } else {
367+ throw new Error ( 'Code point 0x' + toHexString ( codePoint ) + ' not encodable in UTF8.' ) ;
368+ }
369+ }
370+
371+ function writeUTF8 ( codePoint : number , buffer : Uint8Array , pos : number ) : number {
372+
373+ // How many bits needed for codePoint
374+ let byteSize = byteSizeInUTF8 ( codePoint ) ;
375+
376+ // 0xxxxxxx
377+ if ( byteSize === 1 ) {
378+ buffer [ pos ] = codePoint ;
379+ return 1 ;
380+ }
381+
382+ // 110xxxxx 10xxxxxx
383+ // 1110xxxx 10xxxxxx 10xxxxxx
384+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
385+ // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
386+ // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
387+
388+ // first byte
389+ buffer [ pos ] = ( ( 0xFC << ( 6 - byteSize ) ) | ( codePoint >>> ( 6 * ( byteSize - 1 ) ) ) ) & 0xFF ;
390+
391+ // successive bytes
392+ for ( let i = 1 ; i < byteSize ; i ++ ) {
393+ buffer [ pos + i ] = ( 0x80 | ( 0x3F & ( codePoint >>> ( 6 * ( byteSize - i - 1 ) ) ) ) ) & 0xFF ;
394+ }
395+
396+ return byteSize ;
397+ }
398+
399+ function copy ( dest : Uint8Array , destIndex : number , src : Uint8Array , srcIndex : number , count : number ) : number {
400+ const len = Math . min ( dest . byteLength - destIndex , src . byteLength - srcIndex , count ) ;
401+
402+ for ( let i = 0 ; i < len ; i ++ ) {
403+ dest [ destIndex + i ] = src [ srcIndex + i ] ;
404+ }
405+
406+ return len ;
407+ }
408+
409+ function fill ( dest : Uint8Array , index : number = 0 , count : number = dest . byteLength , value : number = 0 ) : void {
410+ for ( let i = 0 ; i < count ; i ++ ) {
411+ dest [ index + i ] = value ;
412+ }
413+ }
414+
415+ //#endregion
0 commit comments