| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 05:08:16 +02:00
										 |  |  | // Package rle implements the run-length encoding used for Ethereum data. | 
					
						
							| 
									
										
										
										
											2014-11-02 23:33:06 +01:00
										 |  |  | package rle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	token             byte = 0xfe | 
					
						
							|  |  |  | 	emptyShaToken          = 0xfd | 
					
						
							|  |  |  | 	emptyListShaToken      = 0xfe | 
					
						
							|  |  |  | 	tokenToken             = 0xff | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-21 18:40:27 +00:00
										 |  |  | var empty = crypto.Keccak256([]byte("")) | 
					
						
							|  |  |  | var emptyList = crypto.Keccak256([]byte{0x80}) | 
					
						
							| 
									
										
										
										
											2014-11-02 23:33:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func Decompress(dat []byte) ([]byte, error) { | 
					
						
							|  |  |  | 	buf := new(bytes.Buffer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < len(dat); i++ { | 
					
						
							|  |  |  | 		if dat[i] == token { | 
					
						
							|  |  |  | 			if i+1 < len(dat) { | 
					
						
							|  |  |  | 				switch dat[i+1] { | 
					
						
							|  |  |  | 				case emptyShaToken: | 
					
						
							|  |  |  | 					buf.Write(empty) | 
					
						
							|  |  |  | 				case emptyListShaToken: | 
					
						
							|  |  |  | 					buf.Write(emptyList) | 
					
						
							|  |  |  | 				case tokenToken: | 
					
						
							|  |  |  | 					buf.WriteByte(token) | 
					
						
							|  |  |  | 				default: | 
					
						
							|  |  |  | 					buf.Write(make([]byte, int(dat[i+1]-2))) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				i++ | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return nil, errors.New("error reading bytes. token encountered without proceeding bytes") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-11-03 00:29:34 +01:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			buf.WriteByte(dat[i]) | 
					
						
							| 
									
										
										
										
											2014-11-02 23:33:06 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buf.Bytes(), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-03 23:45:32 +01:00
										 |  |  | func compressChunk(dat []byte) (ret []byte, n int) { | 
					
						
							| 
									
										
										
										
											2014-11-03 14:59:50 +01:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case dat[0] == token: | 
					
						
							|  |  |  | 		return []byte{token, tokenToken}, 1 | 
					
						
							|  |  |  | 	case len(dat) > 1 && dat[0] == 0x0 && dat[1] == 0x0: | 
					
						
							|  |  |  | 		j := 0 | 
					
						
							|  |  |  | 		for j <= 254 && j < len(dat) { | 
					
						
							|  |  |  | 			if dat[j] != 0 { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			j++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return []byte{token, byte(j + 2)}, j | 
					
						
							|  |  |  | 	case len(dat) >= 32: | 
					
						
							| 
									
										
										
										
											2017-01-06 16:44:20 +01:00
										 |  |  | 		if dat[0] == empty[0] && bytes.Equal(dat[:32], empty) { | 
					
						
							| 
									
										
										
										
											2014-11-03 14:59:50 +01:00
										 |  |  | 			return []byte{token, emptyShaToken}, 32 | 
					
						
							| 
									
										
										
										
											2017-01-06 16:44:20 +01:00
										 |  |  | 		} else if dat[0] == emptyList[0] && bytes.Equal(dat[:32], emptyList) { | 
					
						
							| 
									
										
										
										
											2014-11-03 14:59:50 +01:00
										 |  |  | 			return []byte{token, emptyListShaToken}, 32 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return dat[:1], 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-02 23:33:06 +01:00
										 |  |  | func Compress(dat []byte) []byte { | 
					
						
							|  |  |  | 	buf := new(bytes.Buffer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-03 14:59:50 +01:00
										 |  |  | 	i := 0 | 
					
						
							|  |  |  | 	for i < len(dat) { | 
					
						
							| 
									
										
										
										
											2014-11-03 23:45:32 +01:00
										 |  |  | 		b, n := compressChunk(dat[i:]) | 
					
						
							| 
									
										
										
										
											2014-11-03 14:59:50 +01:00
										 |  |  | 		buf.Write(b) | 
					
						
							|  |  |  | 		i += n | 
					
						
							| 
									
										
										
										
											2014-11-02 23:33:06 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buf.Bytes() | 
					
						
							|  |  |  | } |