From d30dfc89bf1b673b2fdc0638766b930adaec228c Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 29 Mar 2025 00:47:55 +0900 Subject: feat(blog/nuldoc): migrate syntax highlighter from highlight.js to shiki.js --- .../index.html | 707 +++++++++++---------- 1 file changed, 363 insertions(+), 344 deletions(-) (limited to 'vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder') diff --git a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html index 4255b561..11831bdf 100644 --- a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html +++ b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html @@ -13,8 +13,7 @@ PNG 画像の最小構成エンコーダを実装する|REPL: Rest-Eat-Program Loop - - +
@@ -98,44 +97,46 @@ 以下のソースコードをベースにする。今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ image/png を用いる。

-
package main
-
-import (
-	"image"
-	_ "image/png"
-	"io"
-	"os"
-)
-
-func main() {
-	inFile, err := os.Open("input.png")
-	if err != nil {
-		panic(err)
-	}
-	defer inFile.Close()
-
-	img, _, err := image.Decode(inFile)
-	if err != nil {
-		panic(err)
-	}
-
-	outFile, err := os.Create("output.png")
-	if err != nil {
-		panic(err)
-	}
-	defer outFile.Close()
-
-	writePng(outFile, img)
-}
-
-func writePng(w io.Writer, img image.Image) {
-	width := uint32(img.Bounds().Dx())
-	height := uint32(img.Bounds().Dy())
-	writeSignature(w)
-	writeChunkIhdr(w, width, height)
-	writeChunkIdat(w, width, height, img)
-	writeChunkIend(w)
-}
+
+
package main
+
+import (
+	"image"
+	_ "image/png"
+	"io"
+	"os"
+)
+
+func main() {
+	inFile, err := os.Open("input.png")
+	if err != nil {
+		panic(err)
+	}
+	defer inFile.Close()
+
+	img, _, err := image.Decode(inFile)
+	if err != nil {
+		panic(err)
+	}
+
+	outFile, err := os.Create("output.png")
+	if err != nil {
+		panic(err)
+	}
+	defer outFile.Close()
+
+	writePng(outFile, img)
+}
+
+func writePng(w io.Writer, img image.Image) {
+	width := uint32(img.Bounds().Dx())
+	height := uint32(img.Bounds().Dy())
+	writeSignature(w)
+	writeChunkIhdr(w, width, height)
+	writeChunkIdat(w, width, height, img)
+	writeChunkIend(w)
+}
+

以降は、writeSignaturewriteChunkIhdr などを実装していく。 @@ -189,21 +190,23 @@ writeSignature の実装はこちら:

-
import "encoding/binary"
-
-func writeSignature(w io.Writer) {
-	sig := [8]uint8{
-		0x89,
-		0x50, // P
-		0x4E, // N
-		0x47, // G
-		0x0D, // CR
-		0x0A, // LF
-		0x1A, // EOF (^Z)
-		0x0A, // LF
-	}
-	binary.Write(w, binary.BigEndian, sig)
-}
+
+
import "encoding/binary"
+
+func writeSignature(w io.Writer) {
+	sig := [8]uint8{
+		0x89,
+		0x50, // P
+		0x4E, // N
+		0x47, // G
+		0x0D, // CR
+		0x0A, // LF
+		0x1A, // EOF (^Z)
+		0x0A, // LF
+	}
+	binary.Write(w, binary.BigEndian, sig)
+}
+

encoding/binary パッケージの binary.Write を使い、固定の 8 バイトを書き込む。 @@ -238,55 +241,59 @@ CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では hash/crc32 パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている (D. Sample CRC implementation) ので、これを Go に移植する。

-
var (
-	crcTable         [256]uint32
-	crcTableComputed bool
-)
-
-func makeCrcTable() {
-	for n := 0; n < 256; n++ {
-		c := uint32(n)
-		for k := 0; k < 8; k++ {
-			if (c & 1) != 0 {
-				c = 0xEDB88320 ^ (c >> 1)
-			} else {
-				c = c >> 1
-			}
-		}
-		crcTable[n] = c
-	}
-	crcTableComputed = true
-}
-
-func updateCrc(crc uint32, buf []byte) uint32 {
-	if !crcTableComputed {
-		makeCrcTable()
-	}
-
-	c := crc
-	for n := 0; n < len(buf); n++ {
-		c = crcTable[(c^uint32(buf[n]))&0xFF] ^ (c >> 8)
-	}
-	return c
-}
-
-func crc(buf []byte) uint32 {
-	return updateCrc(0xFFFFFFFF, buf) ^ 0xFFFFFFFF
-}
+
+
var (
+	crcTable         [256]uint32
+	crcTableComputed bool
+)
+
+func makeCrcTable() {
+	for n := 0; n < 256; n++ {
+		c := uint32(n)
+		for k := 0; k < 8; k++ {
+			if (c & 1) != 0 {
+				c = 0xEDB88320 ^ (c >> 1)
+			} else {
+				c = c >> 1
+			}
+		}
+		crcTable[n] = c
+	}
+	crcTableComputed = true
+}
+
+func updateCrc(crc uint32, buf []byte) uint32 {
+	if !crcTableComputed {
+		makeCrcTable()
+	}
+
+	c := crc
+	for n := 0; n < len(buf); n++ {
+		c = crcTable[(c^uint32(buf[n]))&0xFF] ^ (c >> 8)
+	}
+	return c
+}
+
+func crc(buf []byte) uint32 {
+	return updateCrc(0xFFFFFFFF, buf) ^ 0xFFFFFFFF
+}
+

できた crc 関数を使って、chunk 一般を書き込む関数も用意しておこう。

-
func writeChunk(w io.Writer, chunkType string, data []byte) {
-	typeAndData := make([]byte, 0, len(chunkType)+len(data))
-	typeAndData = append(typeAndData, []byte(chunkType)...)
-	typeAndData = append(typeAndData, data...)
-
-	binary.Write(w, binary.BigEndian, uint32(len(data)))
-	binary.Write(w, binary.BigEndian, typeAndData)
-	binary.Write(w, binary.BigEndian, crc(typeAndData))
-}
+
+
func writeChunk(w io.Writer, chunkType string, data []byte) {
+	typeAndData := make([]byte, 0, len(chunkType)+len(data))
+	typeAndData = append(typeAndData, []byte(chunkType)...)
+	typeAndData = append(typeAndData, data...)
+
+	binary.Write(w, binary.BigEndian, uint32(len(data)))
+	binary.Write(w, binary.BigEndian, typeAndData)
+	binary.Write(w, binary.BigEndian, crc(typeAndData))
+}
+

仕様どおり、chunkTypedata から CRC を計算し、data の長さと合わせて書き込んでいる。PNG では基本的に big endian を使うことに注意する。 @@ -372,20 +379,22 @@ 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。

-
import "bytes"
-
-func writeChunkIhdr(w io.Writer, width, height uint32) {
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.BigEndian, width)
-	binary.Write(&buf, binary.BigEndian, height)
-	binary.Write(&buf, binary.BigEndian, uint8(8))
-	binary.Write(&buf, binary.BigEndian, uint8(2))
-	binary.Write(&buf, binary.BigEndian, uint8(0))
-	binary.Write(&buf, binary.BigEndian, uint8(0))
-	binary.Write(&buf, binary.BigEndian, uint8(0))
-
-	writeChunk(w, "IHDR", buf.Bytes())
-}
+
+
import "bytes"
+
+func writeChunkIhdr(w io.Writer, width, height uint32) {
+	var buf bytes.Buffer
+	binary.Write(&buf, binary.BigEndian, width)
+	binary.Write(&buf, binary.BigEndian, height)
+	binary.Write(&buf, binary.BigEndian, uint8(8))
+	binary.Write(&buf, binary.BigEndian, uint8(2))
+	binary.Write(&buf, binary.BigEndian, uint8(0))
+	binary.Write(&buf, binary.BigEndian, uint8(0))
+	binary.Write(&buf, binary.BigEndian, uint8(0))
+
+	writeChunk(w, "IHDR", buf.Bytes())
+}
+
@@ -426,22 +435,24 @@ Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている (9. Appendix: Sample code) ので、Go に移植する。

-
const adler32Base = 65521
-
-func updateAdler32(adler uint32, buf []byte) uint32 {
-	s1 := adler & 0xFFFF
-	s2 := (adler >> 16) & 0xFFFF
-
-	for n := 0; n < len(buf); n++ {
-		s1 = (s1 + uint32(buf[n])) % adler32Base
-		s2 = (s2 + s1) % adler32Base
-	}
-	return (s2 << 16) + s1
-}
-
-func adler32(buf []byte) uint32 {
-	return updateAdler32(1, buf)
-}
+
+
const adler32Base = 65521
+
+func updateAdler32(adler uint32, buf []byte) uint32 {
+	s1 := adler & 0xFFFF
+	s2 := (adler >> 16) & 0xFFFF
+
+	for n := 0; n < len(buf); n++ {
+		s1 = (s1 + uint32(buf[n])) % adler32Base
+		s2 = (s2 + s1) % adler32Base
+	}
+	return (s2 << 16) + s1
+}
+
+func adler32(buf []byte) uint32 {
+	return updateAdler32(1, buf)
+}
+

「データ」の部分には圧縮したデータが入るのだが、真面目に deflate アルゴリズムを実装する必要はない。Zlib には無圧縮のデータブロックを格納することができるので、これを使う。本来は、データの圧縮効率の悪いランダムなデータをそのまま格納するためのものだが、今回は deflate の実装をサボるために使う。 @@ -473,30 +484,32 @@ 実際にこの手抜き zlib を実装したものがこちら:

-
func encodeZlib(data []byte) []byte {
-	var buf bytes.Buffer
-
-	binary.Write(&buf, binary.BigEndian, uint8(0x78))
-	binary.Write(&buf, binary.BigEndian, uint8(0x01))
-	blockSize := 65535
-	isFinalBlock := false
-	for i := 0; !isFinalBlock; i++ {
-		var block []byte
-		if len(data) <= (i+1)*blockSize {
-			block = data[i*blockSize:]
-			isFinalBlock = true
-		} else {
-			block = data[i*blockSize : (i+1)*blockSize]
-		}
-		binary.Write(&buf, binary.BigEndian, isFinalBlock)
-		binary.Write(&buf, binary.LittleEndian, uint16(len(block)))
-		binary.Write(&buf, binary.LittleEndian, uint16(^len(block)))
-		binary.Write(&buf, binary.LittleEndian, block)
-	}
-	binary.Write(&buf, binary.BigEndian, adler32(data))
-
-	return buf.Bytes()
-}
+
+
func encodeZlib(data []byte) []byte {
+	var buf bytes.Buffer
+
+	binary.Write(&buf, binary.BigEndian, uint8(0x78))
+	binary.Write(&buf, binary.BigEndian, uint8(0x01))
+	blockSize := 65535
+	isFinalBlock := false
+	for i := 0; !isFinalBlock; i++ {
+		var block []byte
+		if len(data) <= (i+1)*blockSize {
+			block = data[i*blockSize:]
+			isFinalBlock = true
+		} else {
+			block = data[i*blockSize : (i+1)*blockSize]
+		}
+		binary.Write(&buf, binary.BigEndian, isFinalBlock)
+		binary.Write(&buf, binary.LittleEndian, uint16(len(block)))
+		binary.Write(&buf, binary.LittleEndian, uint16(^len(block)))
+		binary.Write(&buf, binary.LittleEndian, block)
+	}
+	binary.Write(&buf, binary.BigEndian, adler32(data))
+
+	return buf.Bytes()
+}
+
@@ -513,20 +526,22 @@ 先ほどの encodeZlib も使って実際に実装したものがこちら:

-
func writeChunkIdat(w io.Writer, width, height uint32, img image.Image) {
-	var pixels bytes.Buffer
-	for y := uint32(0); y < height; y++ {
-		binary.Write(&pixels, binary.BigEndian, uint8(0))
-		for x := uint32(0); x < width; x++ {
-			r, g, b, _ := img.At(int(x), int(y)).RGBA()
-			binary.Write(&pixels, binary.BigEndian, uint8(r))
-			binary.Write(&pixels, binary.BigEndian, uint8(g))
-			binary.Write(&pixels, binary.BigEndian, uint8(b))
-		}
-	}
-
-	writeChunk(w, "IDAT", encodeZlib(pixels.Bytes()))
-}
+
+
func writeChunkIdat(w io.Writer, width, height uint32, img image.Image) {
+	var pixels bytes.Buffer
+	for y := uint32(0); y < height; y++ {
+		binary.Write(&pixels, binary.BigEndian, uint8(0))
+		for x := uint32(0); x < width; x++ {
+			r, g, b, _ := img.At(int(x), int(y)).RGBA()
+			binary.Write(&pixels, binary.BigEndian, uint8(r))
+			binary.Write(&pixels, binary.BigEndian, uint8(g))
+			binary.Write(&pixels, binary.BigEndian, uint8(b))
+		}
+	}
+
+	writeChunk(w, "IDAT", encodeZlib(pixels.Bytes()))
+}
+
@@ -540,9 +555,11 @@ 特に追加のデータはなく、必要なのは chunk type の IEND くらいなので実装は簡単:

-
func writeChunkIend(w io.Writer) {
-	writeChunk(w, "IEND", nil)
-}
+
+
func writeChunkIend(w io.Writer) {
+	writeChunk(w, "IEND", nil)
+}
+
@@ -552,180 +569,182 @@ 最後に全ソースコードを再掲しておく。

-
package main
-
-import (
-	"bytes"
-	"encoding/binary"
-	"image"
-	_ "image/png"
-	"io"
-	"os"
-)
-
-func main() {
-	inFile, err := os.Open("input.png")
-	if err != nil {
-		panic(err)
-	}
-	defer inFile.Close()
-
-	img, _, err := image.Decode(inFile)
-	if err != nil {
-		panic(err)
-	}
-
-	outFile, err := os.Create("output.png")
-	if err != nil {
-		panic(err)
-	}
-	defer outFile.Close()
-
-	writePng(outFile, img)
-}
-
-func writePng(w io.Writer, img image.Image) {
-	width := uint32(img.Bounds().Dx())
-	height := uint32(img.Bounds().Dy())
-	writeSignature(w)
-	writeChunkIhdr(w, width, height)
-	writeChunkIdat(w, width, height, img)
-	writeChunkIend(w)
-}
-
-func writeSignature(w io.Writer) {
-	sig := [8]uint8{
-		0x89,
-		0x50, // P
-		0x4E, // N
-		0x47, // G
-		0x0D, // CR
-		0x0A, // LF
-		0x1A, // EOF (^Z)
-		0x0A, // LF
-	}
-	binary.Write(w, binary.BigEndian, sig)
-}
-
-func writeChunkIhdr(w io.Writer, width, height uint32) {
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.BigEndian, width)
-	binary.Write(&buf, binary.BigEndian, height)
-	binary.Write(&buf, binary.BigEndian, uint8(8))
-	binary.Write(&buf, binary.BigEndian, uint8(2))
-	binary.Write(&buf, binary.BigEndian, uint8(0))
-	binary.Write(&buf, binary.BigEndian, uint8(0))
-	binary.Write(&buf, binary.BigEndian, uint8(0))
-
-	writeChunk(w, "IHDR", buf.Bytes())
-}
-
-func writeChunkIdat(w io.Writer, width, height uint32, img image.Image) {
-	var pixels bytes.Buffer
-	for y := uint32(0); y < height; y++ {
-		binary.Write(&pixels, binary.BigEndian, uint8(0))
-		for x := uint32(0); x < width; x++ {
-			r, g, b, _ := img.At(int(x), int(y)).RGBA()
-			binary.Write(&pixels, binary.BigEndian, uint8(r))
-			binary.Write(&pixels, binary.BigEndian, uint8(g))
-			binary.Write(&pixels, binary.BigEndian, uint8(b))
-		}
-	}
-
-	writeChunk(w, "IDAT", encodeZlib(pixels.Bytes()))
-}
-
-func encodeZlib(data []byte) []byte {
-	var buf bytes.Buffer
-
-	binary.Write(&buf, binary.BigEndian, uint8(0x78))
-	binary.Write(&buf, binary.BigEndian, uint8(0x01))
-	blockSize := 65535
-	isFinalBlock := false
-	for i := 0; !isFinalBlock; i++ {
-		var block []byte
-		if len(data) <= (i+1)*blockSize {
-			block = data[i*blockSize:]
-			isFinalBlock = true
-		} else {
-			block = data[i*blockSize : (i+1)*blockSize]
-		}
-		binary.Write(&buf, binary.BigEndian, isFinalBlock)
-		binary.Write(&buf, binary.LittleEndian, uint16(len(block)))
-		binary.Write(&buf, binary.LittleEndian, uint16(^len(block)))
-		binary.Write(&buf, binary.LittleEndian, block)
-	}
-	binary.Write(&buf, binary.BigEndian, adler32(data))
-
-	return buf.Bytes()
-}
-
-func writeChunkIend(w io.Writer) {
-	writeChunk(w, "IEND", nil)
-}
-
-func writeChunk(w io.Writer, chunkType string, data []byte) {
-	typeAndData := make([]byte, 0, len(chunkType)+len(data))
-	typeAndData = append(typeAndData, []byte(chunkType)...)
-	typeAndData = append(typeAndData, data...)
-
-	binary.Write(w, binary.BigEndian, uint32(len(data)))
-	binary.Write(w, binary.BigEndian, typeAndData)
-	binary.Write(w, binary.BigEndian, crc(typeAndData))
-}
-
-var (
-	crcTable         [256]uint32
-	crcTableComputed bool
-)
-
-func makeCrcTable() {
-	for n := 0; n < 256; n++ {
-		c := uint32(n)
-		for k := 0; k < 8; k++ {
-			if (c & 1) != 0 {
-				c = 0xEDB88320 ^ (c >> 1)
-			} else {
-				c = c >> 1
-			}
-		}
-		crcTable[n] = c
-	}
-	crcTableComputed = true
-}
-
-func updateCrc(crc uint32, buf []byte) uint32 {
-	if !crcTableComputed {
-		makeCrcTable()
-	}
-
-	c := crc
-	for n := 0; n < len(buf); n++ {
-		c = crcTable[(c^uint32(buf[n]))&0xFF] ^ (c >> 8)
-	}
-	return c
-}
-
-func crc(buf []byte) uint32 {
-	return updateCrc(0xFFFFFFFF, buf) ^ 0xFFFFFFFF
-}
-
-const adler32Base = 65521
-
-func updateAdler32(adler uint32, buf []byte) uint32 {
-	s1 := adler & 0xFFFF
-	s2 := (adler >> 16) & 0xFFFF
-
-	for n := 0; n < len(buf); n++ {
-		s1 = (s1 + uint32(buf[n])) % adler32Base
-		s2 = (s2 + s1) % adler32Base
-	}
-	return (s2 << 16) + s1
-}
-
-func adler32(buf []byte) uint32 {
-	return updateAdler32(1, buf)
-}
+
+
package main
+
+import (
+	"bytes"
+	"encoding/binary"
+	"image"
+	_ "image/png"
+	"io"
+	"os"
+)
+
+func main() {
+	inFile, err := os.Open("input.png")
+	if err != nil {
+		panic(err)
+	}
+	defer inFile.Close()
+
+	img, _, err := image.Decode(inFile)
+	if err != nil {
+		panic(err)
+	}
+
+	outFile, err := os.Create("output.png")
+	if err != nil {
+		panic(err)
+	}
+	defer outFile.Close()
+
+	writePng(outFile, img)
+}
+
+func writePng(w io.Writer, img image.Image) {
+	width := uint32(img.Bounds().Dx())
+	height := uint32(img.Bounds().Dy())
+	writeSignature(w)
+	writeChunkIhdr(w, width, height)
+	writeChunkIdat(w, width, height, img)
+	writeChunkIend(w)
+}
+
+func writeSignature(w io.Writer) {
+	sig := [8]uint8{
+		0x89,
+		0x50, // P
+		0x4E, // N
+		0x47, // G
+		0x0D, // CR
+		0x0A, // LF
+		0x1A, // EOF (^Z)
+		0x0A, // LF
+	}
+	binary.Write(w, binary.BigEndian, sig)
+}
+
+func writeChunkIhdr(w io.Writer, width, height uint32) {
+	var buf bytes.Buffer
+	binary.Write(&buf, binary.BigEndian, width)
+	binary.Write(&buf, binary.BigEndian, height)
+	binary.Write(&buf, binary.BigEndian, uint8(8))
+	binary.Write(&buf, binary.BigEndian, uint8(2))
+	binary.Write(&buf, binary.BigEndian, uint8(0))
+	binary.Write(&buf, binary.BigEndian, uint8(0))
+	binary.Write(&buf, binary.BigEndian, uint8(0))
+
+	writeChunk(w, "IHDR", buf.Bytes())
+}
+
+func writeChunkIdat(w io.Writer, width, height uint32, img image.Image) {
+	var pixels bytes.Buffer
+	for y := uint32(0); y < height; y++ {
+		binary.Write(&pixels, binary.BigEndian, uint8(0))
+		for x := uint32(0); x < width; x++ {
+			r, g, b, _ := img.At(int(x), int(y)).RGBA()
+			binary.Write(&pixels, binary.BigEndian, uint8(r))
+			binary.Write(&pixels, binary.BigEndian, uint8(g))
+			binary.Write(&pixels, binary.BigEndian, uint8(b))
+		}
+	}
+
+	writeChunk(w, "IDAT", encodeZlib(pixels.Bytes()))
+}
+
+func encodeZlib(data []byte) []byte {
+	var buf bytes.Buffer
+
+	binary.Write(&buf, binary.BigEndian, uint8(0x78))
+	binary.Write(&buf, binary.BigEndian, uint8(0x01))
+	blockSize := 65535
+	isFinalBlock := false
+	for i := 0; !isFinalBlock; i++ {
+		var block []byte
+		if len(data) <= (i+1)*blockSize {
+			block = data[i*blockSize:]
+			isFinalBlock = true
+		} else {
+			block = data[i*blockSize : (i+1)*blockSize]
+		}
+		binary.Write(&buf, binary.BigEndian, isFinalBlock)
+		binary.Write(&buf, binary.LittleEndian, uint16(len(block)))
+		binary.Write(&buf, binary.LittleEndian, uint16(^len(block)))
+		binary.Write(&buf, binary.LittleEndian, block)
+	}
+	binary.Write(&buf, binary.BigEndian, adler32(data))
+
+	return buf.Bytes()
+}
+
+func writeChunkIend(w io.Writer) {
+	writeChunk(w, "IEND", nil)
+}
+
+func writeChunk(w io.Writer, chunkType string, data []byte) {
+	typeAndData := make([]byte, 0, len(chunkType)+len(data))
+	typeAndData = append(typeAndData, []byte(chunkType)...)
+	typeAndData = append(typeAndData, data...)
+
+	binary.Write(w, binary.BigEndian, uint32(len(data)))
+	binary.Write(w, binary.BigEndian, typeAndData)
+	binary.Write(w, binary.BigEndian, crc(typeAndData))
+}
+
+var (
+	crcTable         [256]uint32
+	crcTableComputed bool
+)
+
+func makeCrcTable() {
+	for n := 0; n < 256; n++ {
+		c := uint32(n)
+		for k := 0; k < 8; k++ {
+			if (c & 1) != 0 {
+				c = 0xEDB88320 ^ (c >> 1)
+			} else {
+				c = c >> 1
+			}
+		}
+		crcTable[n] = c
+	}
+	crcTableComputed = true
+}
+
+func updateCrc(crc uint32, buf []byte) uint32 {
+	if !crcTableComputed {
+		makeCrcTable()
+	}
+
+	c := crc
+	for n := 0; n < len(buf); n++ {
+		c = crcTable[(c^uint32(buf[n]))&0xFF] ^ (c >> 8)
+	}
+	return c
+}
+
+func crc(buf []byte) uint32 {
+	return updateCrc(0xFFFFFFFF, buf) ^ 0xFFFFFFFF
+}
+
+const adler32Base = 65521
+
+func updateAdler32(adler uint32, buf []byte) uint32 {
+	s1 := adler & 0xFFFF
+	s2 := (adler >> 16) & 0xFFFF
+
+	for n := 0; n < len(buf); n++ {
+		s1 = (s1 + uint32(buf[n])) % adler32Base
+		s2 = (s2 + s1) % adler32Base
+	}
+	return (s2 << 16) + s1
+}
+
+func adler32(buf []byte) uint32 {
+	return updateAdler32(1, buf)
+}
+
-- cgit v1.2.3-70-g09d2