1// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2016 The Go Authors.  All rights reserved.
4// https://github.com/golang/protobuf
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10//     * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//     * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16//     * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32// conformance implements the conformance test subprocess protocol as
33// documented in conformance.proto.
34package main
35
36import (
37	"encoding/binary"
38	"fmt"
39	"io"
40	"os"
41
42	pb "github.com/golang/protobuf/conformance/internal/conformance_proto"
43	"github.com/golang/protobuf/jsonpb"
44	"github.com/golang/protobuf/proto"
45)
46
47func main() {
48	var sizeBuf [4]byte
49	inbuf := make([]byte, 0, 4096)
50	outbuf := proto.NewBuffer(nil)
51	for {
52		if _, err := io.ReadFull(os.Stdin, sizeBuf[:]); err == io.EOF {
53			break
54		} else if err != nil {
55			fmt.Fprintln(os.Stderr, "go conformance: read request:", err)
56			os.Exit(1)
57		}
58		size := binary.LittleEndian.Uint32(sizeBuf[:])
59		if int(size) > cap(inbuf) {
60			inbuf = make([]byte, size)
61		}
62		inbuf = inbuf[:size]
63		if _, err := io.ReadFull(os.Stdin, inbuf); err != nil {
64			fmt.Fprintln(os.Stderr, "go conformance: read request:", err)
65			os.Exit(1)
66		}
67
68		req := new(pb.ConformanceRequest)
69		if err := proto.Unmarshal(inbuf, req); err != nil {
70			fmt.Fprintln(os.Stderr, "go conformance: parse request:", err)
71			os.Exit(1)
72		}
73		res := handle(req)
74
75		if err := outbuf.Marshal(res); err != nil {
76			fmt.Fprintln(os.Stderr, "go conformance: marshal response:", err)
77			os.Exit(1)
78		}
79		binary.LittleEndian.PutUint32(sizeBuf[:], uint32(len(outbuf.Bytes())))
80		if _, err := os.Stdout.Write(sizeBuf[:]); err != nil {
81			fmt.Fprintln(os.Stderr, "go conformance: write response:", err)
82			os.Exit(1)
83		}
84		if _, err := os.Stdout.Write(outbuf.Bytes()); err != nil {
85			fmt.Fprintln(os.Stderr, "go conformance: write response:", err)
86			os.Exit(1)
87		}
88		outbuf.Reset()
89	}
90}
91
92var jsonMarshaler = jsonpb.Marshaler{
93	OrigName: true,
94}
95
96func handle(req *pb.ConformanceRequest) *pb.ConformanceResponse {
97	var err error
98	var msg pb.TestAllTypes
99	switch p := req.Payload.(type) {
100	case *pb.ConformanceRequest_ProtobufPayload:
101		err = proto.Unmarshal(p.ProtobufPayload, &msg)
102	case *pb.ConformanceRequest_JsonPayload:
103		err = jsonpb.UnmarshalString(p.JsonPayload, &msg)
104	default:
105		return &pb.ConformanceResponse{
106			Result: &pb.ConformanceResponse_RuntimeError{
107				RuntimeError: "unknown request payload type",
108			},
109		}
110	}
111	if err != nil {
112		return &pb.ConformanceResponse{
113			Result: &pb.ConformanceResponse_ParseError{
114				ParseError: err.Error(),
115			},
116		}
117	}
118	switch req.RequestedOutputFormat {
119	case pb.WireFormat_PROTOBUF:
120		p, err := proto.Marshal(&msg)
121		if err != nil {
122			return &pb.ConformanceResponse{
123				Result: &pb.ConformanceResponse_SerializeError{
124					SerializeError: err.Error(),
125				},
126			}
127		}
128		return &pb.ConformanceResponse{
129			Result: &pb.ConformanceResponse_ProtobufPayload{
130				ProtobufPayload: p,
131			},
132		}
133	case pb.WireFormat_JSON:
134		p, err := jsonMarshaler.MarshalToString(&msg)
135		if err != nil {
136			return &pb.ConformanceResponse{
137				Result: &pb.ConformanceResponse_SerializeError{
138					SerializeError: err.Error(),
139				},
140			}
141		}
142		return &pb.ConformanceResponse{
143			Result: &pb.ConformanceResponse_JsonPayload{
144				JsonPayload: p,
145			},
146		}
147	default:
148		return &pb.ConformanceResponse{
149			Result: &pb.ConformanceResponse_RuntimeError{
150				RuntimeError: "unknown output format",
151			},
152		}
153	}
154}
155