1
// Copyright 2010 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
13
var armorHeaderSep = []byte(": ")
14
var blockEnd = []byte("\n=")
15
var newline = []byte("\n")
16
var armorEndOfLineOut = []byte("-----\n")
18
// writeSlices writes its arguments to the given Writer.
19
func writeSlices(out io.Writer, slices ...[]byte) (err os.Error) {
20
for _, s := range slices {
21
_, err := out.Write(s)
29
// lineBreaker breaks data across several lines, all of the same byte length
30
// (except possibly the last). Lines are broken with a single '\n'.
31
type lineBreaker struct {
39
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
41
lineLength: lineLength,
42
line: make([]byte, lineLength),
48
func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
55
if l.used == 0 && l.haveWritten {
56
_, err = l.out.Write([]byte{'\n'})
62
if l.used+len(b) < l.lineLength {
63
l.used += copy(l.line[l.used:], b)
68
_, err = l.out.Write(l.line[0:l.used])
72
excess := l.lineLength - l.used
75
_, err = l.out.Write(b[0:excess])
80
_, err = l.Write(b[excess:])
84
func (l *lineBreaker) Close() (err os.Error) {
86
_, err = l.out.Write(l.line[0:l.used])
95
// encoding keeps track of a running CRC24 over the data which has been written
96
// to it and outputs a OpenPGP checksum when closed, followed by an armor
99
// It's built into a stack of io.Writers:
100
// encoding -> base64 encoder -> lineBreaker -> out
101
type encoding struct {
109
func (e *encoding) Write(data []byte) (n int, err os.Error) {
110
e.crc = crc24(e.crc, data)
111
return e.b64.Write(data)
114
func (e *encoding) Close() (err os.Error) {
121
var checksumBytes [3]byte
122
checksumBytes[0] = byte(e.crc >> 16)
123
checksumBytes[1] = byte(e.crc >> 8)
124
checksumBytes[2] = byte(e.crc)
126
var b64ChecksumBytes [4]byte
127
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
129
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
132
// Encode returns a WriteCloser which will encode the data written to it in
134
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err os.Error) {
135
bType := []byte(blockType)
136
err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
141
for k, v := range headers {
142
err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
148
_, err = out.Write(newline)
155
breaker: newLineBreaker(out, 64),
159
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)