~ubuntu-branches/ubuntu/vivid/juju-core/vivid-updates

« back to all changes in this revision

Viewing changes to src/code.google.com/p/go.crypto/openpgp/armor/encode.go

  • Committer: Package Import Robot
  • Author(s): Curtis C. Hovey
  • Date: 2015-09-29 19:43:29 UTC
  • mfrom: (47.1.4 wily-proposed)
  • Revision ID: package-import@ubuntu.com-20150929194329-9y496tbic30hc7vp
Tags: 1.24.6-0ubuntu1~15.04.1
Backport of 1.24.6 from wily. (LP: #1500916, #1497087)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
4
 
 
5
 
package armor
6
 
 
7
 
import (
8
 
        "encoding/base64"
9
 
        "io"
10
 
)
11
 
 
12
 
var armorHeaderSep = []byte(": ")
13
 
var blockEnd = []byte("\n=")
14
 
var newline = []byte("\n")
15
 
var armorEndOfLineOut = []byte("-----\n")
16
 
 
17
 
// writeSlices writes its arguments to the given Writer.
18
 
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
19
 
        for _, s := range slices {
20
 
                _, err = out.Write(s)
21
 
                if err != nil {
22
 
                        return err
23
 
                }
24
 
        }
25
 
        return
26
 
}
27
 
 
28
 
// lineBreaker breaks data across several lines, all of the same byte length
29
 
// (except possibly the last). Lines are broken with a single '\n'.
30
 
type lineBreaker struct {
31
 
        lineLength  int
32
 
        line        []byte
33
 
        used        int
34
 
        out         io.Writer
35
 
        haveWritten bool
36
 
}
37
 
 
38
 
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
39
 
        return &lineBreaker{
40
 
                lineLength: lineLength,
41
 
                line:       make([]byte, lineLength),
42
 
                used:       0,
43
 
                out:        out,
44
 
        }
45
 
}
46
 
 
47
 
func (l *lineBreaker) Write(b []byte) (n int, err error) {
48
 
        n = len(b)
49
 
 
50
 
        if n == 0 {
51
 
                return
52
 
        }
53
 
 
54
 
        if l.used == 0 && l.haveWritten {
55
 
                _, err = l.out.Write([]byte{'\n'})
56
 
                if err != nil {
57
 
                        return
58
 
                }
59
 
        }
60
 
 
61
 
        if l.used+len(b) < l.lineLength {
62
 
                l.used += copy(l.line[l.used:], b)
63
 
                return
64
 
        }
65
 
 
66
 
        l.haveWritten = true
67
 
        _, err = l.out.Write(l.line[0:l.used])
68
 
        if err != nil {
69
 
                return
70
 
        }
71
 
        excess := l.lineLength - l.used
72
 
        l.used = 0
73
 
 
74
 
        _, err = l.out.Write(b[0:excess])
75
 
        if err != nil {
76
 
                return
77
 
        }
78
 
 
79
 
        _, err = l.Write(b[excess:])
80
 
        return
81
 
}
82
 
 
83
 
func (l *lineBreaker) Close() (err error) {
84
 
        if l.used > 0 {
85
 
                _, err = l.out.Write(l.line[0:l.used])
86
 
                if err != nil {
87
 
                        return
88
 
                }
89
 
        }
90
 
 
91
 
        return
92
 
}
93
 
 
94
 
// encoding keeps track of a running CRC24 over the data which has been written
95
 
// to it and outputs a OpenPGP checksum when closed, followed by an armor
96
 
// trailer.
97
 
//
98
 
// It's built into a stack of io.Writers:
99
 
//    encoding -> base64 encoder -> lineBreaker -> out
100
 
type encoding struct {
101
 
        out       io.Writer
102
 
        breaker   *lineBreaker
103
 
        b64       io.WriteCloser
104
 
        crc       uint32
105
 
        blockType []byte
106
 
}
107
 
 
108
 
func (e *encoding) Write(data []byte) (n int, err error) {
109
 
        e.crc = crc24(e.crc, data)
110
 
        return e.b64.Write(data)
111
 
}
112
 
 
113
 
func (e *encoding) Close() (err error) {
114
 
        err = e.b64.Close()
115
 
        if err != nil {
116
 
                return
117
 
        }
118
 
        e.breaker.Close()
119
 
 
120
 
        var checksumBytes [3]byte
121
 
        checksumBytes[0] = byte(e.crc >> 16)
122
 
        checksumBytes[1] = byte(e.crc >> 8)
123
 
        checksumBytes[2] = byte(e.crc)
124
 
 
125
 
        var b64ChecksumBytes [4]byte
126
 
        base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
127
 
 
128
 
        return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
129
 
}
130
 
 
131
 
// Encode returns a WriteCloser which will encode the data written to it in
132
 
// OpenPGP armor.
133
 
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
134
 
        bType := []byte(blockType)
135
 
        err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
136
 
        if err != nil {
137
 
                return
138
 
        }
139
 
 
140
 
        for k, v := range headers {
141
 
                err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
142
 
                if err != nil {
143
 
                        return
144
 
                }
145
 
        }
146
 
 
147
 
        _, err = out.Write(newline)
148
 
        if err != nil {
149
 
                return
150
 
        }
151
 
 
152
 
        e := &encoding{
153
 
                out:       out,
154
 
                breaker:   newLineBreaker(out, 64),
155
 
                crc:       crc24Init,
156
 
                blockType: bType,
157
 
        }
158
 
        e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
159
 
        return e, nil
160
 
}