summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-05-04 01:04:51 +0200
committerOndřej Surý <ondrej@sury.org>2011-05-04 01:04:51 +0200
commit14cda8f405d55947c0a3fae0852b04af8405eae0 (patch)
treefa304ad78ef1a8166b3dcd964e1a63091d4c9db2 /src
parentc1ba1a0fec4aed430709030f98a3bdb90bfeea16 (diff)
downloadgolang-14cda8f405d55947c0a3fae0852b04af8405eae0.tar.gz
Imported Upstream version 57upstream/57
Diffstat (limited to 'src')
-rw-r--r--src/Make.cmd2
-rw-r--r--src/cmd/5a/lex.c53
-rw-r--r--src/cmd/6a/lex.c53
-rw-r--r--src/cmd/8a/lex.c53
-rw-r--r--src/cmd/cc/lex.c58
-rwxr-xr-xsrc/cmd/prof/gopprof9
-rw-r--r--src/pkg/compress/flate/deflate.go29
-rw-r--r--src/pkg/http/pprof/pprof.go14
-rw-r--r--src/pkg/http/transfer.go20
-rw-r--r--src/pkg/image/image.go58
-rw-r--r--src/pkg/image/jpeg/writer.go32
-rw-r--r--src/pkg/image/jpeg/writer_test.go28
-rw-r--r--src/pkg/image/png/reader.go22
-rw-r--r--src/pkg/image/png/writer.go29
-rw-r--r--src/pkg/image/png/writer_test.go40
-rw-r--r--src/pkg/mime/multipart/multipart.go197
-rw-r--r--src/pkg/mime/multipart/multipart_test.go125
-rw-r--r--src/pkg/reflect/all_test.go22
-rw-r--r--src/pkg/reflect/value.go9
-rw-r--r--src/pkg/runtime/linux/arm/sys.s15
-rw-r--r--src/pkg/sync/atomic/asm_linux_arm.s21
-rw-r--r--src/pkg/xml/read.go9
-rw-r--r--src/pkg/xml/xml_test.go81
23 files changed, 564 insertions, 415 deletions
diff --git a/src/Make.cmd b/src/Make.cmd
index e769e3072..26c3ca2fc 100644
--- a/src/Make.cmd
+++ b/src/Make.cmd
@@ -25,7 +25,7 @@ _go_.$O: $(GOFILES) $(PREREQ)
install: $(TARGDIR)/$(TARG)
$(TARGDIR)/$(TARG): $(TARG)
- cp -f $(TARG) $(TARGDIR)
+ mkdir -p $(TARGDIR) && cp -f $(TARG) $(TARGDIR)
CLEANFILES+=$(TARG) _test _testmain.go
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index dbee3657f..a04cda220 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -50,7 +50,7 @@ void
main(int argc, char *argv[])
{
char *p;
- int nout, nproc, i, c;
+ int c;
thechar = '5';
thestring = "arm";
@@ -94,46 +94,10 @@ main(int argc, char *argv[])
print("usage: %ca [-options] file.s\n", thechar);
errorexit();
}
- if(argc > 1 && systemtype(Windows)){
- print("can't assemble multiple files on windows\n");
+ if(argc > 1){
+ print("can't assemble multiple files\n");
errorexit();
}
- if(argc > 1 && !systemtype(Windows)) {
- nproc = 1;
- if(p = getenv("NPROC"))
- nproc = atol(p); /* */
- c = 0;
- nout = 0;
- for(;;) {
- Waitmsg *w;
-
- while(nout < nproc && argc > 0) {
- i = fork();
- if(i < 0) {
- fprint(2, "fork: %r\n");
- errorexit();
- }
- if(i == 0) {
- print("%s:\n", *argv);
- if(assemble(*argv))
- errorexit();
- exits(0);
- }
- nout++;
- argc--;
- argv++;
- }
- w = wait();
- if(w == nil) {
- if(c)
- errorexit();
- exits(0);
- }
- if(w->msg[0])
- c++;
- nout--;
- }
- }
if(assemble(argv[0]))
errorexit();
exits(0);
@@ -142,7 +106,7 @@ main(int argc, char *argv[])
int
assemble(char *file)
{
- char *ofile, incfile[20], *p;
+ char *ofile, *p;
int i, of;
ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
@@ -167,15 +131,6 @@ assemble(char *file)
} else
outfile = "/dev/null";
}
- p = getenv("INCLUDE");
- if(p) {
- setinclude(p);
- } else {
- if(systemtype(Plan9)) {
- sprint(incfile,"/%s/include", thestring);
- setinclude(strdup(incfile));
- }
- }
of = create(outfile, OWRITE, 0664);
if(of < 0) {
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index 37144c888..b4c7d0c2c 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -56,7 +56,7 @@ void
main(int argc, char *argv[])
{
char *p;
- int nout, nproc, i, c;
+ int c;
thechar = '6';
thestring = "amd64";
@@ -96,46 +96,10 @@ main(int argc, char *argv[])
print("usage: %ca [-options] file.s\n", thechar);
errorexit();
}
- if(argc > 1 && systemtype(Windows)){
- print("can't assemble multiple files on windows\n");
+ if(argc > 1){
+ print("can't assemble multiple files\n");
errorexit();
}
- if(argc > 1 && !systemtype(Windows)) {
- nproc = 1;
- if(p = getenv("NPROC"))
- nproc = atol(p); /* */
- c = 0;
- nout = 0;
- for(;;) {
- Waitmsg *w;
-
- while(nout < nproc && argc > 0) {
- i = fork();
- if(i < 0) {
- fprint(2, "fork: %r\n");
- errorexit();
- }
- if(i == 0) {
- print("%s:\n", *argv);
- if(assemble(*argv))
- errorexit();
- exits(0);
- }
- nout++;
- argc--;
- argv++;
- }
- w = wait();
- if(w == nil) {
- if(c)
- errorexit();
- exits(0);
- }
- if(w->msg[0])
- c++;
- nout--;
- }
- }
if(assemble(argv[0]))
errorexit();
exits(0);
@@ -144,7 +108,7 @@ main(int argc, char *argv[])
int
assemble(char *file)
{
- char *ofile, incfile[20], *p;
+ char *ofile, *p;
int i, of;
ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
@@ -169,15 +133,6 @@ assemble(char *file)
} else
outfile = "/dev/null";
}
- p = getenv("INCLUDE");
- if(p) {
- setinclude(p);
- } else {
- if(systemtype(Plan9)) {
- sprint(incfile,"/%s/include", thestring);
- setinclude(strdup(incfile));
- }
- }
of = create(outfile, OWRITE, 0664);
if(of < 0) {
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index ca18b69ce..078861877 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -56,7 +56,7 @@ void
main(int argc, char *argv[])
{
char *p;
- int nout, nproc, i, c;
+ int c;
thechar = '8';
thestring = "386";
@@ -96,46 +96,10 @@ main(int argc, char *argv[])
print("usage: %ca [-options] file.s\n", thechar);
errorexit();
}
- if(argc > 1 && systemtype(Windows)){
- print("can't assemble multiple files on windows\n");
+ if(argc > 1){
+ print("can't assemble multiple files\n");
errorexit();
}
- if(argc > 1 && !systemtype(Windows)) {
- nproc = 1;
- if(p = getenv("NPROC"))
- nproc = atol(p); /* */
- c = 0;
- nout = 0;
- for(;;) {
- Waitmsg *w;
-
- while(nout < nproc && argc > 0) {
- i = fork();
- if(i < 0) {
- fprint(2, "fork: %r\n");
- errorexit();
- }
- if(i == 0) {
- print("%s:\n", *argv);
- if(assemble(*argv))
- errorexit();
- exits(0);
- }
- nout++;
- argc--;
- argv++;
- }
- w = wait();
- if(w == nil) {
- if(c)
- errorexit();
- exits(0);
- }
- if(w->msg[0])
- c++;
- nout--;
- }
- }
if(assemble(argv[0]))
errorexit();
exits(0);
@@ -144,7 +108,7 @@ main(int argc, char *argv[])
int
assemble(char *file)
{
- char *ofile, incfile[20], *p;
+ char *ofile, *p;
int i, of;
ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
@@ -169,15 +133,6 @@ assemble(char *file)
} else
outfile = "/dev/null";
}
- p = getenv("INCLUDE");
- if(p) {
- setinclude(p);
- } else {
- if(systemtype(Plan9)) {
- sprint(incfile,"/%s/include", thestring);
- setinclude(strdup(incfile));
- }
- }
of = create(outfile, OWRITE, 0664);
if(of < 0) {
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index dba8ff634..71cc89bf0 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -88,7 +88,7 @@ void
main(int argc, char *argv[])
{
char **defs, *p;
- int nproc, nout, i, c, ndef;
+ int c, ndef;
ensuresymb(NSYMB);
memset(debug, 0, sizeof(debug));
@@ -142,51 +142,10 @@ main(int argc, char *argv[])
print("usage: %cc [-options] files\n", thechar);
errorexit();
}
- if(argc > 1 && systemtype(Windows)){
- print("can't compile multiple files on windows\n");
+ if(argc > 1){
+ print("can't compile multiple files\n");
errorexit();
}
- if(argc > 1 && !systemtype(Windows)) {
- nproc = 1;
- /*
- * if we're writing acid to standard output, don't compile
- * concurrently, to avoid interleaving output.
- */
- if(((!debug['a'] && !debug['q'] && !debug['Q']) || debug['n']) &&
- (p = getenv("NPROC")) != nil)
- nproc = atol(p); /* */
- c = 0;
- nout = 0;
- for(;;) {
- Waitmsg *w;
-
- while(nout < nproc && argc > 0) {
- i = fork();
- if(i < 0) {
- print("cannot create a process\n");
- errorexit();
- }
- if(i == 0) {
- fprint(2, "%s:\n", *argv);
- if (compile(*argv, defs, ndef))
- errorexit();
- exits(0);
- }
- nout++;
- argc--;
- argv++;
- }
- w = wait();
- if(w == nil) {
- if(c)
- errorexit();
- exits(0);
- }
- if(w->msg[0])
- c++;
- nout--;
- }
- }
if(argc == 0)
c = compile("stdin", defs, ndef);
@@ -201,7 +160,7 @@ main(int argc, char *argv[])
int
compile(char *file, char **defs, int ndef)
{
- char *ofile, incfile[20];
+ char *ofile;
char *p, **av, opt[256];
int i, c, fd[2];
static int first = 1;
@@ -236,15 +195,6 @@ compile(char *file, char **defs, int ndef)
outfile = "/dev/null";
}
- if(p = getenv("INCLUDE")) {
- setinclude(p);
- } else {
- if(systemtype(Plan9)) {
- sprint(incfile, "/%s/include", thestring);
- setinclude(strdup(incfile));
- setinclude("/sys/include");
- }
- }
if (first)
Binit(&diagbuf, 1, OWRITE);
/*
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
index 8fa00cbe8..8863fc623 100755
--- a/src/cmd/prof/gopprof
+++ b/src/cmd/prof/gopprof
@@ -2880,17 +2880,18 @@ sub FetchSymbols {
my @toask = @pcs;
while (@toask > 0) {
my $n = @toask;
- if ($n > 49) { $n = 49; }
+ # NOTE(rsc): Limiting the number of PCs requested per round
+ # used to be necessary, but I think it was a bug in
+ # debug/pprof/symbol's implementation. Leaving here
+ # in case I am wrong.
+ # if ($n > 49) { $n = 49; }
my @thisround = @toask[0..$n];
-my $t = @toask;
-print STDERR "$n $t\n";
@toask = @toask[($n+1)..(@toask-1)];
my $post_data = join("+", sort((map {"0x" . "$_"} @thisround)));
open(POSTFILE, ">$main::tmpfile_sym");
print POSTFILE $post_data;
close(POSTFILE);
-print STDERR "SYMBL!\n";
my $url = SymbolPageURL();
$url = ResolveRedirectionForCurl($url);
my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
diff --git a/src/pkg/compress/flate/deflate.go b/src/pkg/compress/flate/deflate.go
index e5b2beaef..a02a5e8d9 100644
--- a/src/pkg/compress/flate/deflate.go
+++ b/src/pkg/compress/flate/deflate.go
@@ -143,10 +143,18 @@ func (d *compressor) fillWindow(index int) (int, os.Error) {
d.blockStart = math.MaxInt32
}
for i, h := range d.hashHead {
- d.hashHead[i] = max(h-wSize, -1)
+ v := h - wSize
+ if v < -1 {
+ v = -1
+ }
+ d.hashHead[i] = v
}
for i, h := range d.hashPrev {
- d.hashPrev[i] = max(h-wSize, -1)
+ v := -h - wSize
+ if v < -1 {
+ v = -1
+ }
+ d.hashPrev[i] = v
}
}
count, err := d.r.Read(d.window[d.windowEnd:])
@@ -177,10 +185,18 @@ func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
// Try to find a match starting at index whose length is greater than prevSize.
// We only look at chainCount possibilities before giving up.
func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
- win := d.window[0 : pos+min(maxMatchLength, lookahead)]
+ minMatchLook := maxMatchLength
+ if lookahead < minMatchLook {
+ minMatchLook = lookahead
+ }
+
+ win := d.window[0 : pos+minMatchLook]
// We quit when we get a match that's at least nice long
- nice := min(d.niceMatch, len(win)-pos)
+ nice := len(win) - pos
+ if d.niceMatch < nice {
+ nice = d.niceMatch
+ }
// If we've got a match that's good enough, only look in 1/4 the chain.
tries := d.maxChainLength
@@ -344,9 +360,12 @@ Loop:
}
prevLength := length
prevOffset := offset
- minIndex := max(index-maxOffset, 0)
length = minMatchLength - 1
offset = 0
+ minIndex := index - maxOffset
+ if minIndex < 0 {
+ minIndex = 0
+ }
if chainHead >= minIndex &&
(isFastDeflate && lookahead > minMatchLength-1 ||
diff --git a/src/pkg/http/pprof/pprof.go b/src/pkg/http/pprof/pprof.go
index bc79e2183..917c7f877 100644
--- a/src/pkg/http/pprof/pprof.go
+++ b/src/pkg/http/pprof/pprof.go
@@ -26,6 +26,7 @@ package pprof
import (
"bufio"
+ "bytes"
"fmt"
"http"
"os"
@@ -88,10 +89,14 @@ func Profile(w http.ResponseWriter, r *http.Request) {
func Symbol(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ // We have to read the whole POST body before
+ // writing any output. Buffer the output here.
+ var buf bytes.Buffer
+
// We don't know how many symbols we have, but we
// do have symbol information. Pprof only cares whether
// this number is 0 (no symbols available) or > 0.
- fmt.Fprintf(w, "num_symbols: 1\n")
+ fmt.Fprintf(&buf, "num_symbols: 1\n")
var b *bufio.Reader
if r.Method == "POST" {
@@ -109,14 +114,19 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
if pc != 0 {
f := runtime.FuncForPC(uintptr(pc))
if f != nil {
- fmt.Fprintf(w, "%#x %s\n", pc, f.Name())
+ fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
}
}
// Wait until here to check for err; the last
// symbol will have an err because it doesn't end in +.
if err != nil {
+ if err != os.EOF {
+ fmt.Fprintf(&buf, "reading request: %v\n", err)
+ }
break
}
}
+
+ w.Write(buf.Bytes())
}
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index 98c32bab6..0fa8bed43 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -439,9 +439,29 @@ type body struct {
hdr interface{} // non-nil (Response or Request) value means read trailer
r *bufio.Reader // underlying wire-format reader for the trailer
closing bool // is the connection to be closed after reading body?
+ closed bool
+}
+
+// ErrBodyReadAfterClose is returned when reading a Request Body after
+// the body has been closed. This typically happens when the body is
+// read after an HTTP Handler calls WriteHeader or Write on its
+// ResponseWriter.
+var ErrBodyReadAfterClose = os.NewError("http: invalid Read on closed request Body")
+
+func (b *body) Read(p []byte) (n int, err os.Error) {
+ if b.closed {
+ return 0, ErrBodyReadAfterClose
+ }
+ return b.Reader.Read(p)
}
func (b *body) Close() os.Error {
+ if b.closed {
+ return nil
+ }
+ defer func() {
+ b.closed = true
+ }()
if b.hdr == nil && b.closing {
// no trailer and closing the connection next.
// no point in reading to EOF.
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index 5f398a304..222d21ade 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -51,6 +51,13 @@ func (p *RGBA) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
}
+func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *RGBA) Opaque() bool {
if p.Rect.Empty() {
@@ -103,6 +110,13 @@ func (p *RGBA64) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
}
+func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *RGBA64) Opaque() bool {
if p.Rect.Empty() {
@@ -155,6 +169,13 @@ func (p *NRGBA) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
}
+func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *NRGBA) Opaque() bool {
if p.Rect.Empty() {
@@ -207,6 +228,13 @@ func (p *NRGBA64) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
}
+func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *NRGBA64) Opaque() bool {
if p.Rect.Empty() {
@@ -252,13 +280,20 @@ func (p *Alpha) At(x, y int) Color {
return p.Pix[y*p.Stride+x]
}
-func (p *Alpha) Set(x, y int, c Color) {
+func (p *Alpha) Set(x, y int, c AlphaColor) {
if !p.Rect.Contains(Point{x, y}) {
return
}
p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
}
+func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Alpha) Opaque() bool {
if p.Rect.Empty() {
@@ -311,6 +346,13 @@ func (p *Alpha16) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
}
+func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Alpha16) Opaque() bool {
if p.Rect.Empty() {
@@ -363,6 +405,13 @@ func (p *Gray) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
}
+func (p *Gray) SetGray(x, y int, c GrayColor) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Gray) Opaque() bool {
return true
@@ -401,6 +450,13 @@ func (p *Gray16) Set(x, y int, c Color) {
p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
}
+func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = c
+}
+
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Gray16) Opaque() bool {
return true
diff --git a/src/pkg/image/jpeg/writer.go b/src/pkg/image/jpeg/writer.go
index 505cce04f..52b3dc4e2 100644
--- a/src/pkg/image/jpeg/writer.go
+++ b/src/pkg/image/jpeg/writer.go
@@ -391,6 +391,31 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
}
}
+// rgbaToYCbCr is a specialized version of toYCbCr for image.RGBA images.
+func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block) {
+ b := m.Bounds()
+ xmax := b.Max.X - 1
+ ymax := b.Max.Y - 1
+ for j := 0; j < 8; j++ {
+ sj := p.Y + j
+ if sj > ymax {
+ sj = ymax
+ }
+ yoff := sj * m.Stride
+ for i := 0; i < 8; i++ {
+ sx := p.X + i
+ if sx > xmax {
+ sx = xmax
+ }
+ col := &m.Pix[yoff+sx]
+ yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
+ yBlock[8*j+i] = int(yy)
+ cbBlock[8*j+i] = int(cb)
+ crBlock[8*j+i] = int(cr)
+ }
+ }
+}
+
// scale scales the 16x16 region represented by the 4 src blocks to the 8x8
// dst block.
func scale(dst *block, src *[4]block) {
@@ -431,13 +456,18 @@ func (e *encoder) writeSOS(m image.Image) {
prevDCY, prevDCCb, prevDCCr int
)
bounds := m.Bounds()
+ rgba, _ := m.(*image.RGBA)
for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
for i := 0; i < 4; i++ {
xOff := (i & 1) * 8
yOff := (i & 2) * 4
p := image.Point{x + xOff, y + yOff}
- toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i])
+ if rgba != nil {
+ rgbaToYCbCr(rgba, p, &yBlock, &cbBlock[i], &crBlock[i])
+ } else {
+ toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i])
+ }
prevDCY = e.writeBlock(&yBlock, 0, prevDCY)
}
scale(&cBlock, &cbBlock)
diff --git a/src/pkg/image/jpeg/writer_test.go b/src/pkg/image/jpeg/writer_test.go
index 00922dd5c..7aec70f01 100644
--- a/src/pkg/image/jpeg/writer_test.go
+++ b/src/pkg/image/jpeg/writer_test.go
@@ -8,6 +8,8 @@ import (
"bytes"
"image"
"image/png"
+ "io/ioutil"
+ "rand"
"os"
"testing"
)
@@ -85,3 +87,29 @@ func TestWriter(t *testing.T) {
}
}
}
+
+func BenchmarkEncodeRGBOpaque(b *testing.B) {
+ b.StopTimer()
+ img := image.NewRGBA(640, 480)
+ // Set all pixels to 0xFF alpha to force opaque mode.
+ bo := img.Bounds()
+ rnd := rand.New(rand.NewSource(123))
+ for y := bo.Min.Y; y < bo.Max.Y; y++ {
+ for x := bo.Min.X; x < bo.Max.X; x++ {
+ img.Set(x, y, image.RGBAColor{
+ uint8(rnd.Intn(256)),
+ uint8(rnd.Intn(256)),
+ uint8(rnd.Intn(256)),
+ 255})
+ }
+ }
+ if !img.Opaque() {
+ panic("expected image to be opaque")
+ }
+ b.SetBytes(640 * 480 * 4)
+ b.StartTimer()
+ options := &Options{Quality: 90}
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img, options)
+ }
+}
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
index b30a951c1..8c76afa72 100644
--- a/src/pkg/image/png/reader.go
+++ b/src/pkg/image/png/reader.go
@@ -378,7 +378,7 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
for x := 0; x < d.width; x += 8 {
b := cdat[x/8]
for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
- gray.Set(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
+ gray.SetGray(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
b <<= 1
}
}
@@ -386,7 +386,7 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
for x := 0; x < d.width; x += 4 {
b := cdat[x/4]
for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
- gray.Set(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
+ gray.SetGray(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
b <<= 2
}
}
@@ -394,22 +394,22 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
for x := 0; x < d.width; x += 2 {
b := cdat[x/2]
for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
- gray.Set(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
+ gray.SetGray(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
b <<= 4
}
}
case cbG8:
for x := 0; x < d.width; x++ {
- gray.Set(x, y, image.GrayColor{cdat[x]})
+ gray.SetGray(x, y, image.GrayColor{cdat[x]})
}
case cbGA8:
for x := 0; x < d.width; x++ {
ycol := cdat[2*x+0]
- nrgba.Set(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
+ nrgba.SetNRGBA(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
for x := 0; x < d.width; x++ {
- rgba.Set(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
+ rgba.SetRGBA(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
}
case cbP1:
for x := 0; x < d.width; x += 8 {
@@ -456,25 +456,25 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
}
case cbTCA8:
for x := 0; x < d.width; x++ {
- nrgba.Set(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
+ nrgba.SetNRGBA(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
}
case cbG16:
for x := 0; x < d.width; x++ {
ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- gray16.Set(x, y, image.Gray16Color{ycol})
+ gray16.SetGray16(x, y, image.Gray16Color{ycol})
}
case cbGA16:
for x := 0; x < d.width; x++ {
ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
- nrgba64.Set(x, y, image.NRGBA64Color{ycol, ycol, ycol, acol})
+ nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{ycol, ycol, ycol, acol})
}
case cbTC16:
for x := 0; x < d.width; x++ {
rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- rgba64.Set(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
+ rgba64.SetRGBA64(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
}
case cbTCA16:
for x := 0; x < d.width; x++ {
@@ -482,7 +482,7 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
- nrgba64.Set(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
+ nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
}
}
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
index 081d06bf5..2d593f6a7 100644
--- a/src/pkg/image/png/writer.go
+++ b/src/pkg/image/png/writer.go
@@ -263,7 +263,12 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
defer zw.Close()
bpp := 0 // Bytes per pixel.
+
+ // Used by fast paths for common image types
var paletted *image.Paletted
+ var rgba *image.RGBA
+ rgba, _ = m.(*image.RGBA)
+
switch cb {
case cbG8:
bpp = 1
@@ -303,12 +308,24 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
cr[0][x+1] = c.Y
}
case cbTC8:
- for x := b.Min.X; x < b.Max.X; x++ {
- // We have previously verified that the alpha value is fully opaque.
- r, g, b, _ := m.At(x, y).RGBA()
- cr[0][3*x+1] = uint8(r >> 8)
- cr[0][3*x+2] = uint8(g >> 8)
- cr[0][3*x+3] = uint8(b >> 8)
+ // We have previously verified that the alpha value is fully opaque.
+ cr0 := cr[0]
+ if rgba != nil {
+ yoff := y * rgba.Stride
+ xoff := 3*b.Min.X + 1
+ for _, color := range rgba.Pix[yoff+b.Min.X : yoff+b.Max.X] {
+ cr0[xoff] = color.R
+ cr0[xoff+1] = color.G
+ cr0[xoff+2] = color.B
+ xoff += 3
+ }
+ } else {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ r, g, b, _ := m.At(x, y).RGBA()
+ cr0[3*x+1] = uint8(r >> 8)
+ cr0[3*x+2] = uint8(g >> 8)
+ cr0[3*x+3] = uint8(b >> 8)
+ }
}
case cbP8:
rowOffset := y * paletted.Stride
diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go
index 4d9929f31..6b054aaa8 100644
--- a/src/pkg/image/png/writer_test.go
+++ b/src/pkg/image/png/writer_test.go
@@ -5,10 +5,10 @@
package png
import (
- "bytes"
"fmt"
"image"
"io"
+ "io/ioutil"
"os"
"testing"
)
@@ -81,10 +81,42 @@ func BenchmarkEncodePaletted(b *testing.B) {
image.RGBAColor{0, 0, 0, 255},
image.RGBAColor{255, 255, 255, 255},
})
+ b.SetBytes(640 * 480 * 1)
b.StartTimer()
- buffer := new(bytes.Buffer)
for i := 0; i < b.N; i++ {
- buffer.Reset()
- Encode(buffer, img)
+ Encode(ioutil.Discard, img)
+ }
+}
+
+func BenchmarkEncodeRGBOpaque(b *testing.B) {
+ b.StopTimer()
+ img := image.NewRGBA(640, 480)
+ // Set all pixels to 0xFF alpha to force opaque mode.
+ bo := img.Bounds()
+ for y := bo.Min.Y; y < bo.Max.Y; y++ {
+ for x := bo.Min.X; x < bo.Max.X; x++ {
+ img.Set(x, y, image.RGBAColor{0, 0, 0, 255})
+ }
+ }
+ if !img.Opaque() {
+ panic("expected image to be opaque")
+ }
+ b.SetBytes(640 * 480 * 4)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img)
+ }
+}
+
+func BenchmarkEncodeRGBA(b *testing.B) {
+ b.StopTimer()
+ img := image.NewRGBA(640, 480)
+ if img.Opaque() {
+ panic("expected image to not be opaque")
+ }
+ b.SetBytes(640 * 480 * 4)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img)
}
}
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index e0b747c3f..60329fe17 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -15,13 +15,13 @@ package multipart
import (
"bufio"
"bytes"
+ "fmt"
"io"
"io/ioutil"
"mime"
"net/textproto"
"os"
"regexp"
- "strings"
)
var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
@@ -79,25 +79,28 @@ func (p *Part) FormName() string {
// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
func NewReader(reader io.Reader, boundary string) Reader {
+ b := []byte("\r\n--" + boundary + "--")
return &multiReader{
- boundary: boundary,
- dashBoundary: "--" + boundary,
- endLine: "--" + boundary + "--",
- bufReader: bufio.NewReader(reader),
+ bufReader: bufio.NewReader(reader),
+
+ nlDashBoundary: b[:len(b)-2],
+ dashBoundaryDash: b[2:],
+ dashBoundary: b[2 : len(b)-2],
}
}
// Implementation ....
-func newPart(mr *multiReader) (bp *Part, err os.Error) {
- bp = new(Part)
- bp.Header = make(map[string][]string)
- bp.mr = mr
- bp.buffer = new(bytes.Buffer)
- if err = bp.populateHeaders(); err != nil {
- bp = nil
+func newPart(mr *multiReader) (*Part, os.Error) {
+ bp := &Part{
+ Header: make(map[string][]string),
+ mr: mr,
+ buffer: new(bytes.Buffer),
}
- return
+ if err := bp.populateHeaders(); err != nil {
+ return nil, err
+ }
+ return bp, nil
}
func (bp *Part) populateHeaders() os.Error {
@@ -122,44 +125,49 @@ func (bp *Part) populateHeaders() os.Error {
// Read reads the body of a part, after its headers and before the
// next part (if any) begins.
func (bp *Part) Read(p []byte) (n int, err os.Error) {
- for {
- if bp.buffer.Len() >= len(p) {
- // Internal buffer of unconsumed data is large enough for
- // the read request. No need to parse more at the moment.
- break
- }
- if !bp.mr.ensureBufferedLine() {
- return 0, io.ErrUnexpectedEOF
- }
- if bp.mr.bufferedLineIsBoundary() {
- // Don't consume this line
- break
- }
+ if bp.buffer.Len() >= len(p) {
+ // Internal buffer of unconsumed data is large enough for
+ // the read request. No need to parse more at the moment.
+ return bp.buffer.Read(p)
+ }
+ peek, err := bp.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
+ unexpectedEof := err == os.EOF
+ if err != nil && !unexpectedEof {
+ return 0, fmt.Errorf("multipart: Part Read: %v", err)
+ }
+ if peek == nil {
+ panic("nil peek buf")
+ }
- // Write all of this line, except the final CRLF
- s := *bp.mr.bufferedLine
- if strings.HasSuffix(s, "\r\n") {
- bp.mr.consumeLine()
- if !bp.mr.ensureBufferedLine() {
- return 0, io.ErrUnexpectedEOF
- }
- if bp.mr.bufferedLineIsBoundary() {
- // The final \r\n isn't ours. It logically belongs
- // to the boundary line which follows.
- bp.buffer.WriteString(s[0 : len(s)-2])
- } else {
- bp.buffer.WriteString(s)
- }
- break
- }
- if strings.HasSuffix(s, "\n") {
- bp.buffer.WriteString(s)
- bp.mr.consumeLine()
- continue
+ // Search the peek buffer for "\r\n--boundary". If found,
+ // consume everything up to the boundary. If not, consume only
+ // as much of the peek buffer as cannot hold the boundary
+ // string.
+ nCopy := 0
+ foundBoundary := false
+ if idx := bytes.Index(peek, bp.mr.nlDashBoundary); idx != -1 {
+ nCopy = idx
+ foundBoundary = true
+ } else if safeCount := len(peek) - len(bp.mr.nlDashBoundary); safeCount > 0 {
+ nCopy = safeCount
+ } else if unexpectedEof {
+ // If we've run out of peek buffer and the boundary
+ // wasn't found (and can't possibly fit), we must have
+ // hit the end of the file unexpectedly.
+ return 0, io.ErrUnexpectedEOF
+ }
+ if nCopy > 0 {
+ if _, err := io.Copyn(bp.buffer, bp.mr.bufReader, int64(nCopy)); err != nil {
+ return 0, err
}
- return 0, os.NewError("multipart parse error during Read; unexpected line: " + s)
}
- return bp.buffer.Read(p)
+ n, err = bp.buffer.Read(p)
+ if err == os.EOF && !foundBoundary {
+ // If the boundary hasn't been reached there's more to
+ // read, so don't pass through an EOF from the buffer
+ err = nil
+ }
+ return
}
func (bp *Part) Close() os.Error {
@@ -168,46 +176,12 @@ func (bp *Part) Close() os.Error {
}
type multiReader struct {
- boundary string
- dashBoundary string // --boundary
- endLine string // --boundary--
+ bufReader *bufio.Reader
- bufferedLine *string
-
- bufReader *bufio.Reader
currentPart *Part
partsRead int
-}
-func (mr *multiReader) eof() bool {
- return mr.bufferedLine == nil &&
- !mr.readLine()
-}
-
-func (mr *multiReader) readLine() bool {
- lineBytes, err := mr.bufReader.ReadSlice('\n')
- if err != nil {
- // TODO: care about err being EOF or not?
- return false
- }
- line := string(lineBytes)
- mr.bufferedLine = &line
- return true
-}
-
-func (mr *multiReader) bufferedLineIsBoundary() bool {
- return strings.HasPrefix(*mr.bufferedLine, mr.dashBoundary)
-}
-
-func (mr *multiReader) ensureBufferedLine() bool {
- if mr.bufferedLine == nil {
- return mr.readLine()
- }
- return true
-}
-
-func (mr *multiReader) consumeLine() {
- mr.bufferedLine = nil
+ nlDashBoundary, dashBoundaryDash, dashBoundary []byte
}
func (mr *multiReader) NextPart() (*Part, os.Error) {
@@ -215,13 +189,14 @@ func (mr *multiReader) NextPart() (*Part, os.Error) {
mr.currentPart.Close()
}
+ expectNewPart := false
for {
- if mr.eof() {
- return nil, io.ErrUnexpectedEOF
+ line, err := mr.bufReader.ReadSlice('\n')
+ if err != nil {
+ return nil, fmt.Errorf("multipart: NextPart: %v", err)
}
- if isBoundaryDelimiterLine(*mr.bufferedLine, mr.dashBoundary) {
- mr.consumeLine()
+ if mr.isBoundaryDelimiterLine(line) {
mr.partsRead++
bp, err := newPart(mr)
if err != nil {
@@ -231,55 +206,67 @@ func (mr *multiReader) NextPart() (*Part, os.Error) {
return bp, nil
}
- if hasPrefixThenNewline(*mr.bufferedLine, mr.endLine) {
- mr.consumeLine()
+ if hasPrefixThenNewline(line, mr.dashBoundaryDash) {
// Expected EOF (no error)
+ // TODO(bradfitz): should return an os.EOF error here, not using nil for errors
return nil, nil
}
+ if expectNewPart {
+ return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
+ }
+
if mr.partsRead == 0 {
// skip line
- mr.consumeLine()
continue
}
- return nil, os.NewError("Unexpected line in Next().")
+ if bytes.Equal(line, []byte("\r\n")) {
+ // Consume the "\r\n" separator between the
+ // body of the previous part and the boundary
+ // line we now expect will follow. (either a
+ // new part or the end boundary)
+ expectNewPart = true
+ continue
+ }
+
+ return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
}
panic("unreachable")
}
-func isBoundaryDelimiterLine(line, dashPrefix string) bool {
+func (mr *multiReader) isBoundaryDelimiterLine(line []byte) bool {
// http://tools.ietf.org/html/rfc2046#section-5.1
// The boundary delimiter line is then defined as a line
// consisting entirely of two hyphen characters ("-",
// decimal value 45) followed by the boundary parameter
// value from the Content-Type header field, optional linear
// whitespace, and a terminating CRLF.
- if !strings.HasPrefix(line, dashPrefix) {
+ if !bytes.HasPrefix(line, mr.dashBoundary) {
return false
}
- if strings.HasSuffix(line, "\r\n") {
- return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-2])
+ if bytes.HasSuffix(line, []byte("\r\n")) {
+ return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-2])
}
// Violate the spec and also support newlines without the
// carriage return...
- if strings.HasSuffix(line, "\n") {
- return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-1])
+ if bytes.HasSuffix(line, []byte("\n")) {
+ return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1])
}
return false
}
-func onlyHorizontalWhitespace(s string) bool {
- for i := 0; i < len(s); i++ {
- if s[i] != ' ' && s[i] != '\t' {
+func onlyHorizontalWhitespace(s []byte) bool {
+ for _, b := range s {
+ if b != ' ' && b != '\t' {
return false
}
}
return true
}
-func hasPrefixThenNewline(s, prefix string) bool {
- return strings.HasPrefix(s, prefix) &&
- (len(s) == len(prefix)+1 && strings.HasSuffix(s, "\n") ||
- len(s) == len(prefix)+2 && strings.HasSuffix(s, "\r\n"))
+func hasPrefixThenNewline(s, prefix []byte) bool {
+ return bytes.HasPrefix(s, prefix) &&
+ (len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
+ len(s) == len(prefix)+2 && bytes.HasSuffix(s, []byte("\r\n")))
}
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
index f8f10f3e1..16249146c 100644
--- a/src/pkg/mime/multipart/multipart_test.go
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -8,38 +8,37 @@ import (
"bytes"
"fmt"
"io"
+ "io/ioutil"
"json"
"os"
- "regexp"
"strings"
"testing"
)
func TestHorizontalWhitespace(t *testing.T) {
- if !onlyHorizontalWhitespace(" \t") {
+ if !onlyHorizontalWhitespace([]byte(" \t")) {
t.Error("expected pass")
}
- if onlyHorizontalWhitespace("foo bar") {
+ if onlyHorizontalWhitespace([]byte("foo bar")) {
t.Error("expected failure")
}
}
func TestBoundaryLine(t *testing.T) {
- boundary := "myBoundary"
- prefix := "--" + boundary
- if !isBoundaryDelimiterLine("--myBoundary\r\n", prefix) {
+ mr := NewReader(strings.NewReader(""), "myBoundary").(*multiReader)
+ if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) {
t.Error("expected")
}
- if !isBoundaryDelimiterLine("--myBoundary \r\n", prefix) {
+ if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \r\n")) {
t.Error("expected")
}
- if !isBoundaryDelimiterLine("--myBoundary \n", prefix) {
+ if !mr.isBoundaryDelimiterLine([]byte("--myBoundary \n")) {
t.Error("expected")
}
- if isBoundaryDelimiterLine("--myBoundary bogus \n", prefix) {
+ if mr.isBoundaryDelimiterLine([]byte("--myBoundary bogus \n")) {
t.Error("expected fail")
}
- if isBoundaryDelimiterLine("--myBoundary bogus--", prefix) {
+ if mr.isBoundaryDelimiterLine([]byte("--myBoundary bogus--")) {
t.Error("expected fail")
}
}
@@ -79,7 +78,9 @@ func TestFormName(t *testing.T) {
}
}
-func TestMultipart(t *testing.T) {
+var longLine = strings.Repeat("\n\n\r\r\r\n\r\000", (1<<20)/8)
+
+func testMultipartBody() string {
testBody := `
This is a multi-part message. This line is ignored.
--MyBoundary
@@ -90,6 +91,10 @@ foo-bar: baz
My value
The end.
--MyBoundary
+name: bigsection
+
+[longline]
+--MyBoundary
Header1: value1b
HEADER2: value2b
foo-bar: bazb
@@ -102,11 +107,26 @@ Line 3 ends in a newline, but just one.
never read data
--MyBoundary--
+
+
+useless trailer
`
- testBody = regexp.MustCompile("\n").ReplaceAllString(testBody, "\r\n")
- bodyReader := strings.NewReader(testBody)
+ testBody = strings.Replace(testBody, "\n", "\r\n", -1)
+ return strings.Replace(testBody, "[longline]", longLine, 1)
+}
+
+func TestMultipart(t *testing.T) {
+ bodyReader := strings.NewReader(testMultipartBody())
+ testMultipart(t, bodyReader)
+}
+
+func TestMultipartSlowInput(t *testing.T) {
+ bodyReader := strings.NewReader(testMultipartBody())
+ testMultipart(t, &slowReader{bodyReader})
+}
- reader := NewReader(bodyReader, "MyBoundary")
+func testMultipart(t *testing.T, r io.Reader) {
+ reader := NewReader(r, "MyBoundary")
buf := new(bytes.Buffer)
// Part1
@@ -125,38 +145,64 @@ never read data
t.Error("Expected Foo-Bar: baz")
}
buf.Reset()
- io.Copy(buf, part)
+ if _, err := io.Copy(buf, part); err != nil {
+ t.Errorf("part 1 copy: %v", err)
+ }
expectEq(t, "My value\r\nThe end.",
buf.String(), "Value of first part")
// Part2
part, err = reader.NextPart()
+ if err != nil {
+ t.Fatalf("Expected part2; got: %v", err)
+ return
+ }
+ if e, g := "bigsection", part.Header.Get("name"); e != g {
+ t.Errorf("part2's name header: expected %q, got %q", e, g)
+ }
+ buf.Reset()
+ if _, err := io.Copy(buf, part); err != nil {
+ t.Errorf("part 2 copy: %v", err)
+ }
+ s := buf.String()
+ if len(s) != len(longLine) {
+ t.Errorf("part2 body expected long line of length %d; got length %d",
+ len(longLine), len(s))
+ }
+ if s != longLine {
+ t.Errorf("part2 long body didn't match")
+ }
+
+ // Part3
+ part, err = reader.NextPart()
if part == nil || err != nil {
- t.Error("Expected part2")
+ t.Error("Expected part3")
return
}
if part.Header.Get("foo-bar") != "bazb" {
t.Error("Expected foo-bar: bazb")
}
buf.Reset()
- io.Copy(buf, part)
+ if _, err := io.Copy(buf, part); err != nil {
+ t.Errorf("part 3 copy: %v", err)
+ }
expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n",
- buf.String(), "Value of second part")
+ buf.String(), "body of part 3")
- // Part3
+ // Part4
part, err = reader.NextPart()
if part == nil || err != nil {
- t.Error("Expected part3 without errors")
+ t.Error("Expected part 4 without errors")
return
}
- // Non-existent part4
+ // Non-existent part5
part, err = reader.NextPart()
if part != nil {
- t.Error("Didn't expect a third part.")
+ t.Error("Didn't expect a fifth part.")
}
if err != nil {
- t.Errorf("Unexpected error getting third part: %v", err)
+ t.Errorf("Unexpected error getting fifth part: %v", err)
}
}
@@ -237,3 +283,36 @@ func TestLineLimit(t *testing.T) {
t.Errorf("expected to read < %d bytes; read %d", maxReadThreshold, mr.n)
}
}
+
+func TestMultipartTruncated(t *testing.T) {
+ testBody := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo-bar: baz
+
+Oh no, premature EOF!
+`
+ body := strings.Replace(testBody, "\n", "\r\n", -1)
+ bodyReader := strings.NewReader(body)
+ r := NewReader(bodyReader, "MyBoundary")
+
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ _, err = io.Copy(ioutil.Discard, part)
+ if err != io.ErrUnexpectedEOF {
+ t.Fatalf("expected error io.ErrUnexpectedEOF; got %v", err)
+ }
+}
+
+type slowReader struct {
+ r io.Reader
+}
+
+func (s *slowReader) Read(p []byte) (int, os.Error) {
+ if len(p) == 0 {
+ return s.r.Read(p)
+ }
+ return s.r.Read(p[:1])
+}
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 5bf65333c..dee3f4915 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -182,7 +182,9 @@ var valueTests = []pair{
}),
"struct { c chan *int32; d float32 }{chan *int32, 0}",
},
- {new(struct{ c func(chan *integer, *int8) }),
+ {new(struct {
+ c func(chan *integer, *int8)
+ }),
"struct { c func(chan *reflect_test.integer, *int8) }{func(chan *reflect_test.integer, *int8)(0)}",
},
{new(struct {
@@ -732,6 +734,24 @@ func TestDeepEqualComplexStructInequality(t *testing.T) {
}
}
+type UnexpT struct {
+ m map[int]int
+}
+
+func TestDeepEqualUnexportedMap(t *testing.T) {
+ // Check that DeepEqual can look at unexported fields.
+ x1 := UnexpT{map[int]int{1: 2}}
+ x2 := UnexpT{map[int]int{1: 2}}
+ if !DeepEqual(&x1, &x2) {
+ t.Error("DeepEqual(x1, x2) = false, want true")
+ }
+
+ y1 := UnexpT{map[int]int{2: 3}}
+ if DeepEqual(&x1, &y1) {
+ t.Error("DeepEqual(x1, y1) = true, want false")
+ }
+}
+
func check2ndField(x interface{}, offs uintptr, t *testing.T) {
s := ValueOf(x)
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 6dffb0783..2c2158a3c 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -958,14 +958,19 @@ func (v Value) MapIndex(key Value) Value {
iv.mustBe(Map)
typ := iv.typ.toType()
+ // Do not require ikey to be exported, so that DeepEqual
+ // and other programs can use all the keys returned by
+ // MapKeys as arguments to MapIndex. If either the map
+ // or the key is unexported, though, the result will be
+ // considered unexported.
+
ikey := key.internal()
- ikey.mustBeExported()
ikey = convertForAssignment("reflect.Value.MapIndex", nil, typ.Key(), ikey)
if iv.word == 0 {
return Value{}
}
- flag := iv.flag & flagRO
+ flag := (iv.flag | ikey.flag) & flagRO
elemType := typ.Elem()
elemWord, ok := mapaccess(iv.word, ikey.word)
if !ok {
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
index d866b0e22..2b5365bd8 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -258,11 +258,22 @@ TEXT cas<>(SB),7,$0
TEXT runtime·cas(SB),7,$0
MOVW valptr+0(FP), R2
MOVW old+4(FP), R0
+casagain:
MOVW new+8(FP), R1
BL cas<>(SB)
- MOVW $0, R0
- MOVW.CS $1, R0
+ BCC cascheck
+ MOVW $1, R0
RET
+cascheck:
+ // Kernel lies; double-check.
+ MOVW valptr+0(FP), R2
+ MOVW old+4(FP), R0
+ MOVW 0(R2), R3
+ CMP R0, R3
+ BEQ casagain
+ MOVW $0, R0
+ RET
+
TEXT runtime·casp(SB),7,$0
B runtime·cas(SB)
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index 5e7aea292..72f8d746b 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -13,6 +13,12 @@
// LR = return address
// The function returns with CS true if the swap happened.
// http://lxr.linux.no/linux+v2.6.37.2/arch/arm/kernel/entry-armv.S#L850
+// On older kernels (before 2.6.24) the function can incorrectly
+// report a conflict, so we have to double-check the compare ourselves
+// and retry if necessary.
+//
+// http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b49c0f24cf6744a3f4fd09289fe7cade349dead5
+//
TEXT cas<>(SB),7,$0
MOVW $0xffff0fc0, PC
@@ -23,12 +29,23 @@ TEXT ·CompareAndSwapInt32(SB),7,$0
TEXT ·CompareAndSwapUint32(SB),7,$0
MOVW valptr+0(FP), R2
MOVW old+4(FP), R0
+casagain:
MOVW new+8(FP), R1
BL cas<>(SB)
- MOVW $0, R0
- MOVW.CS $1, R0
+ BCC cascheck
+ MOVW $1, R0
+casret:
MOVW R0, ret+12(FP)
RET
+cascheck:
+ // Kernel lies; double-check.
+ MOVW valptr+0(FP), R2
+ MOVW old+4(FP), R0
+ MOVW 0(R2), R3
+ CMP R0, R3
+ BEQ casagain
+ MOVW $0, R0
+ B casret
TEXT ·CompareAndSwapUintptr(SB),7,$0
B ·CompareAndSwapUint32(SB)
diff --git a/src/pkg/xml/read.go b/src/pkg/xml/read.go
index 554b2a61b..e2b349c3f 100644
--- a/src/pkg/xml/read.go
+++ b/src/pkg/xml/read.go
@@ -220,13 +220,10 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
}
if pv := val; pv.Kind() == reflect.Ptr {
- if pv.Pointer() == 0 {
- zv := reflect.Zero(pv.Type().Elem())
- pv.Set(zv.Addr())
- val = zv
- } else {
- val = pv.Elem()
+ if pv.IsNil() {
+ pv.Set(reflect.New(pv.Type().Elem()))
}
+ val = pv.Elem()
}
var (
diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go
index a99c1919e..4e51cd53a 100644
--- a/src/pkg/xml/xml_test.go
+++ b/src/pkg/xml/xml_test.go
@@ -329,46 +329,50 @@ func TestSyntax(t *testing.T) {
}
type allScalars struct {
- True1 bool
- True2 bool
- False1 bool
- False2 bool
- Int int
- Int8 int8
- Int16 int16
- Int32 int32
- Int64 int64
- Uint int
- Uint8 uint8
- Uint16 uint16
- Uint32 uint32
- Uint64 uint64
- Uintptr uintptr
- Float32 float32
- Float64 float64
- String string
+ True1 bool
+ True2 bool
+ False1 bool
+ False2 bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint int
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Uintptr uintptr
+ Float32 float32
+ Float64 float64
+ String string
+ PtrString *string
}
var all = allScalars{
- True1: true,
- True2: true,
- False1: false,
- False2: false,
- Int: 1,
- Int8: -2,
- Int16: 3,
- Int32: -4,
- Int64: 5,
- Uint: 6,
- Uint8: 7,
- Uint16: 8,
- Uint32: 9,
- Uint64: 10,
- Uintptr: 11,
- Float32: 13.0,
- Float64: 14.0,
- String: "15",
-}
+ True1: true,
+ True2: true,
+ False1: false,
+ False2: false,
+ Int: 1,
+ Int8: -2,
+ Int16: 3,
+ Int32: -4,
+ Int64: 5,
+ Uint: 6,
+ Uint8: 7,
+ Uint16: 8,
+ Uint32: 9,
+ Uint64: 10,
+ Uintptr: 11,
+ Float32: 13.0,
+ Float64: 14.0,
+ String: "15",
+ PtrString: &sixteen,
+}
+
+var sixteen = "16"
const testScalarsInput = `<allscalars>
<true1>true</true1>
@@ -390,6 +394,7 @@ const testScalarsInput = `<allscalars>
<float32>13.0</float32>
<float64>14.0</float64>
<string>15</string>
+ <ptrstring>16</ptrstring>
</allscalars>`
func TestAllScalars(t *testing.T) {
@@ -401,7 +406,7 @@ func TestAllScalars(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(a, all) {
- t.Errorf("expected %+v got %+v", all, a)
+ t.Errorf("have %+v want %+v", a, all)
}
}