73 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			V
		
	
	
module chunked
 | 
						|
 | 
						|
import strings
 | 
						|
// See: https://en.wikipedia.org/wiki/Chunked_transfer_encoding
 | 
						|
// /////////////////////////////////////////////////////////////
 | 
						|
// The chunk size is transferred as a hexadecimal number
 | 
						|
// followed by \r\n as a line separator,
 | 
						|
// followed by a chunk of data of the given size.
 | 
						|
// The end is marked with a chunk with size 0.
 | 
						|
 | 
						|
struct ChunkScanner {
 | 
						|
mut:
 | 
						|
	pos  int
 | 
						|
	text string
 | 
						|
}
 | 
						|
 | 
						|
fn (mut s ChunkScanner) read_chunk_size() u32 {
 | 
						|
	mut n := u32(0)
 | 
						|
	for {
 | 
						|
		if s.pos >= s.text.len {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		c := s.text[s.pos]
 | 
						|
		if !c.is_hex_digit() {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		n = n << 4
 | 
						|
		n += u32(unhex(c))
 | 
						|
		s.pos++
 | 
						|
	}
 | 
						|
	return n
 | 
						|
}
 | 
						|
 | 
						|
fn unhex(c byte) byte {
 | 
						|
	if `0` <= c && c <= `9` {
 | 
						|
		return c - `0`
 | 
						|
	} else if `a` <= c && c <= `f` {
 | 
						|
		return c - `a` + 10
 | 
						|
	} else if `A` <= c && c <= `F` {
 | 
						|
		return c - `A` + 10
 | 
						|
	}
 | 
						|
	return 0
 | 
						|
}
 | 
						|
 | 
						|
fn (mut s ChunkScanner) skip_crlf() {
 | 
						|
	s.pos += 2
 | 
						|
}
 | 
						|
 | 
						|
fn (mut s ChunkScanner) read_chunk(chunksize u32) string {
 | 
						|
	startpos := s.pos
 | 
						|
	s.pos += int(chunksize)
 | 
						|
	return s.text[startpos..s.pos]
 | 
						|
}
 | 
						|
 | 
						|
pub fn decode(text string) string {
 | 
						|
	mut sb := strings.new_builder(100)
 | 
						|
	mut cscanner := ChunkScanner{
 | 
						|
		pos: 0
 | 
						|
		text: text
 | 
						|
	}
 | 
						|
	for {
 | 
						|
		csize := cscanner.read_chunk_size()
 | 
						|
		if 0 == csize {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		cscanner.skip_crlf()
 | 
						|
		sb.write_string(cscanner.read_chunk(csize))
 | 
						|
		cscanner.skip_crlf()
 | 
						|
	}
 | 
						|
	cscanner.skip_crlf()
 | 
						|
	return sb.str()
 | 
						|
}
 |