vendor in go-criu and dependencies
Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
		
							parent
							
								
									58a26ac9dc
								
							
						
					
					
						commit
						20b5714f35
					
				|  | @ -6,6 +6,7 @@ github.com/Microsoft/hcsshim 43f9725307998e09f2e3816c2c0c36dc98f0c982 | |||
| github.com/blang/semver v3.5.0 | ||||
| github.com/boltdb/bolt master | ||||
| github.com/buger/goterm 2f8dfbc7dbbff5dd1d391ed91482c24df243b2d3 | ||||
| github.com/checkpoint-restore/go-criu master | ||||
| github.com/containerd/cgroups 58556f5ad8448d99a6f7bea69ea4bdb7747cfeb0 | ||||
| github.com/containerd/continuity master | ||||
| github.com/containernetworking/cni v0.7.0-alpha1 | ||||
|  |  | |||
|  | @ -0,0 +1,201 @@ | |||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| 
 | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| 
 | ||||
|    1. Definitions. | ||||
| 
 | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
| 
 | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
| 
 | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
| 
 | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
| 
 | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
| 
 | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
| 
 | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
| 
 | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
| 
 | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
| 
 | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
| 
 | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
| 
 | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
| 
 | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
| 
 | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
| 
 | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
| 
 | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
| 
 | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
| 
 | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
| 
 | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
| 
 | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
| 
 | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
| 
 | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
| 
 | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
| 
 | ||||
|    END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
| 
 | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "{}" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
| 
 | ||||
|    Copyright {yyyy} {name of copyright owner} | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
| 
 | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
|  | @ -0,0 +1,27 @@ | |||
| [](https://travis-ci.org/checkpoint-restore/go-criu) | ||||
| 
 | ||||
| ## go-criu -- Go bindings for [CRIU](https://criu.org/) | ||||
| 
 | ||||
| This repository provides Go bindings for CRIU. The code is based on the Go based PHaul | ||||
| implementation from the CRIU repository. For easier inclusion into other Go projects the | ||||
| CRIU Go bindings have been moved to this repository. | ||||
| 
 | ||||
| The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need | ||||
| to set up all the infrastructure to make the actual RPC connection to CRIU. | ||||
| 
 | ||||
| The following example would print the version of CRIU: | ||||
| ``` | ||||
| 	c := criu.MakeCriu() | ||||
| 	version, err := c.GetCriuVersion() | ||||
| 	fmt.Println(version) | ||||
| ``` | ||||
| or to just check if at least a certain CRIU version is installed: | ||||
| ``` | ||||
| 	c := criu.MakeCriu() | ||||
| 	result, err := c.IsCriuAtLeast(31100) | ||||
| ``` | ||||
| 
 | ||||
| ### License | ||||
| 
 | ||||
| The license of go-criu is the Apache 2.0 license. | ||||
| 
 | ||||
|  | @ -0,0 +1,250 @@ | |||
| package criu | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strconv" | ||||
| 	"syscall" | ||||
| 
 | ||||
| 	"github.com/checkpoint-restore/go-criu/rpc" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| // Criu struct
 | ||||
| type Criu struct { | ||||
| 	swrkCmd *exec.Cmd | ||||
| 	swrkSk  *os.File | ||||
| } | ||||
| 
 | ||||
| // MakeCriu returns the Criu object required for most operations
 | ||||
| func MakeCriu() *Criu { | ||||
| 	return &Criu{} | ||||
| } | ||||
| 
 | ||||
| // Prepare sets up everything for the RPC communication to CRIU
 | ||||
| func (c *Criu) Prepare() error { | ||||
| 	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln") | ||||
| 	syscall.CloseOnExec(fds[0]) | ||||
| 	srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv") | ||||
| 	defer srv.Close() | ||||
| 
 | ||||
| 	args := []string{"swrk", strconv.Itoa(fds[1])} | ||||
| 	cmd := exec.Command("criu", args...) | ||||
| 
 | ||||
| 	err = cmd.Start() | ||||
| 	if err != nil { | ||||
| 		cln.Close() | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	c.swrkCmd = cmd | ||||
| 	c.swrkSk = cln | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Cleanup cleans up
 | ||||
| func (c *Criu) Cleanup() { | ||||
| 	if c.swrkCmd != nil { | ||||
| 		c.swrkSk.Close() | ||||
| 		c.swrkSk = nil | ||||
| 		c.swrkCmd.Wait() | ||||
| 		c.swrkCmd = nil | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) { | ||||
| 	cln := c.swrkSk | ||||
| 	_, err := cln.Write(reqB) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	respB := make([]byte, 2*4096) | ||||
| 	n, err := cln.Read(respB) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return respB, n, nil | ||||
| } | ||||
| 
 | ||||
| func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error { | ||||
| 	resp, err := c.doSwrkWithResp(reqType, opts, nfy) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	respType := resp.GetType() | ||||
| 	if respType != reqType { | ||||
| 		return errors.New("unexpected responce") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) { | ||||
| 	var resp *rpc.CriuResp | ||||
| 
 | ||||
| 	req := rpc.CriuReq{ | ||||
| 		Type: &reqType, | ||||
| 		Opts: opts, | ||||
| 	} | ||||
| 
 | ||||
| 	if nfy != nil { | ||||
| 		opts.NotifyScripts = proto.Bool(true) | ||||
| 	} | ||||
| 
 | ||||
| 	if c.swrkCmd == nil { | ||||
| 		err := c.Prepare() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		defer c.Cleanup() | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		reqB, err := proto.Marshal(&req) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		respB, respS, err := c.sendAndRecv(reqB) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		resp = &rpc.CriuResp{} | ||||
| 		err = proto.Unmarshal(respB[:respS], resp) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		if !resp.GetSuccess() { | ||||
| 			return resp, fmt.Errorf("operation failed (msg:%s err:%d)", | ||||
| 				resp.GetCrErrmsg(), resp.GetCrErrno()) | ||||
| 		} | ||||
| 
 | ||||
| 		respType := resp.GetType() | ||||
| 		if respType != rpc.CriuReqType_NOTIFY { | ||||
| 			break | ||||
| 		} | ||||
| 		if nfy == nil { | ||||
| 			return resp, errors.New("unexpected notify") | ||||
| 		} | ||||
| 
 | ||||
| 		notify := resp.GetNotify() | ||||
| 		switch notify.GetScript() { | ||||
| 		case "pre-dump": | ||||
| 			err = nfy.PreDump() | ||||
| 		case "post-dump": | ||||
| 			err = nfy.PostDump() | ||||
| 		case "pre-restore": | ||||
| 			err = nfy.PreRestore() | ||||
| 		case "post-restore": | ||||
| 			err = nfy.PostRestore(notify.GetPid()) | ||||
| 		case "network-lock": | ||||
| 			err = nfy.NetworkLock() | ||||
| 		case "network-unlock": | ||||
| 			err = nfy.NetworkUnlock() | ||||
| 		case "setup-namespaces": | ||||
| 			err = nfy.SetupNamespaces(notify.GetPid()) | ||||
| 		case "post-setup-namespaces": | ||||
| 			err = nfy.PostSetupNamespaces() | ||||
| 		case "post-resume": | ||||
| 			err = nfy.PostResume() | ||||
| 		default: | ||||
| 			err = nil | ||||
| 		} | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			return resp, err | ||||
| 		} | ||||
| 
 | ||||
| 		req = rpc.CriuReq{ | ||||
| 			Type:          &respType, | ||||
| 			NotifySuccess: proto.Bool(true), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return resp, nil | ||||
| } | ||||
| 
 | ||||
| // Dump dumps a process
 | ||||
| func (c *Criu) Dump(opts rpc.CriuOpts, nfy Notify) error { | ||||
| 	return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy) | ||||
| } | ||||
| 
 | ||||
| // Restore restores a process
 | ||||
| func (c *Criu) Restore(opts rpc.CriuOpts, nfy Notify) error { | ||||
| 	return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy) | ||||
| } | ||||
| 
 | ||||
| // PreDump does a pre-dump
 | ||||
| func (c *Criu) PreDump(opts rpc.CriuOpts, nfy Notify) error { | ||||
| 	return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy) | ||||
| } | ||||
| 
 | ||||
| // StartPageServer starts the page server
 | ||||
| func (c *Criu) StartPageServer(opts rpc.CriuOpts) error { | ||||
| 	return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil) | ||||
| } | ||||
| 
 | ||||
| // StartPageServerChld starts the page server and returns PID and port
 | ||||
| func (c *Criu) StartPageServerChld(opts rpc.CriuOpts) (int, int, error) { | ||||
| 	resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, &opts, nil) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	return int(resp.Ps.GetPid()), int(resp.Ps.GetPort()), nil | ||||
| } | ||||
| 
 | ||||
| // GetCriuVersion executes the VERSION RPC call and returns the version
 | ||||
| // as an integer. Major * 10000 + Minor * 100 + SubLevel
 | ||||
| func (c *Criu) GetCriuVersion() (int, error) { | ||||
| 	resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	if resp.GetType() != rpc.CriuReqType_VERSION { | ||||
| 		return 0, fmt.Errorf("Unexpected CRIU RPC response") | ||||
| 	} | ||||
| 
 | ||||
| 	version := int(*resp.GetVersion().Major) * 10000 | ||||
| 	version += int(*resp.GetVersion().Minor) * 100 | ||||
| 	if resp.GetVersion().Sublevel != nil { | ||||
| 		version += int(*resp.GetVersion().Sublevel) | ||||
| 	} | ||||
| 
 | ||||
| 	if resp.GetVersion().Gitid != nil { | ||||
| 		// taken from runc: if it is a git release -> increase minor by 1
 | ||||
| 		version -= (version % 100) | ||||
| 		version += 100 | ||||
| 	} | ||||
| 
 | ||||
| 	return version, nil | ||||
| } | ||||
| 
 | ||||
| // IsCriuAtLeast checks if the version is at least the same
 | ||||
| // as the parameter version
 | ||||
| func (c *Criu) IsCriuAtLeast(version int) (bool, error) { | ||||
| 	criuVersion, err := c.GetCriuVersion() | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
| 	if criuVersion >= version { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return false, nil | ||||
| } | ||||
|  | @ -0,0 +1,63 @@ | |||
| package criu | ||||
| 
 | ||||
| //Notify interface
 | ||||
| type Notify interface { | ||||
| 	PreDump() error | ||||
| 	PostDump() error | ||||
| 	PreRestore() error | ||||
| 	PostRestore(pid int32) error | ||||
| 	NetworkLock() error | ||||
| 	NetworkUnlock() error | ||||
| 	SetupNamespaces(pid int32) error | ||||
| 	PostSetupNamespaces() error | ||||
| 	PostResume() error | ||||
| } | ||||
| 
 | ||||
| // NoNotify struct
 | ||||
| type NoNotify struct { | ||||
| } | ||||
| 
 | ||||
| // PreDump NoNotify
 | ||||
| func (c NoNotify) PreDump() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // PostDump NoNotify
 | ||||
| func (c NoNotify) PostDump() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // PreRestore NoNotify
 | ||||
| func (c NoNotify) PreRestore() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // PostRestore NoNotify
 | ||||
| func (c NoNotify) PostRestore(pid int32) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // NetworkLock NoNotify
 | ||||
| func (c NoNotify) NetworkLock() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // NetworkUnlock NoNotify
 | ||||
| func (c NoNotify) NetworkUnlock() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // SetupNamespaces NoNotify
 | ||||
| func (c NoNotify) SetupNamespaces(pid int32) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // PostSetupNamespaces NoNotify
 | ||||
| func (c NoNotify) PostSetupNamespaces() error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // PostResume NoNotify
 | ||||
| func (c NoNotify) PostResume() error { | ||||
| 	return nil | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,133 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/checkpoint-restore/go-criu" | ||||
| 	"github.com/checkpoint-restore/go-criu/rpc" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| // TestNfy struct
 | ||||
| type TestNfy struct { | ||||
| 	criu.NoNotify | ||||
| } | ||||
| 
 | ||||
| // PreDump test function
 | ||||
| func (c TestNfy) PreDump() error { | ||||
| 	fmt.Printf("TEST PRE DUMP\n") | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func doDump(c *criu.Criu, pidS string, imgDir string, pre bool, prevImg string) error { | ||||
| 	fmt.Printf("Dumping\n") | ||||
| 	pid, _ := strconv.Atoi(pidS) | ||||
| 	img, err := os.Open(imgDir) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("can't open image dir (%s)", err) | ||||
| 	} | ||||
| 	defer img.Close() | ||||
| 
 | ||||
| 	opts := rpc.CriuOpts{ | ||||
| 		Pid:         proto.Int32(int32(pid)), | ||||
| 		ImagesDirFd: proto.Int32(int32(img.Fd())), | ||||
| 		LogLevel:    proto.Int32(4), | ||||
| 		LogFile:     proto.String("dump.log"), | ||||
| 	} | ||||
| 
 | ||||
| 	if prevImg != "" { | ||||
| 		opts.ParentImg = proto.String(prevImg) | ||||
| 		opts.TrackMem = proto.Bool(true) | ||||
| 	} | ||||
| 
 | ||||
| 	if pre { | ||||
| 		err = c.PreDump(opts, TestNfy{}) | ||||
| 	} else { | ||||
| 		err = c.Dump(opts, TestNfy{}) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("dump fail (%s)", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Usage: test $act $pid $images_dir
 | ||||
| func main() { | ||||
| 	c := criu.MakeCriu() | ||||
| 	// Read out CRIU version
 | ||||
| 	version, err := c.GetCriuVersion() | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	fmt.Println("CRIU version", version) | ||||
| 	// Check if version at least 3.2
 | ||||
| 	result, err := c.IsCriuAtLeast(30200) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	if !result { | ||||
| 		fmt.Println("CRIU too old") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	act := os.Args[1] | ||||
| 	switch act { | ||||
| 	case "dump": | ||||
| 		err := doDump(c, os.Args[2], os.Args[3], false, "") | ||||
| 		if err != nil { | ||||
| 			fmt.Print(err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	case "dump2": | ||||
| 		err := c.Prepare() | ||||
| 		if err != nil { | ||||
| 			fmt.Print(err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 
 | ||||
| 		err = doDump(c, os.Args[2], os.Args[3]+"/pre", true, "") | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("pre-dump failed") | ||||
| 			fmt.Print(err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		err = doDump(c, os.Args[2], os.Args[3], false, "./pre") | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("dump failed") | ||||
| 			fmt.Print(err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 
 | ||||
| 		c.Cleanup() | ||||
| 	case "restore": | ||||
| 		fmt.Printf("Restoring\n") | ||||
| 		img, err := os.Open(os.Args[2]) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("can't open image dir") | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		defer img.Close() | ||||
| 
 | ||||
| 		opts := rpc.CriuOpts{ | ||||
| 			ImagesDirFd: proto.Int32(int32(img.Fd())), | ||||
| 			LogLevel:    proto.Int32(4), | ||||
| 			LogFile:     proto.String("restore.log"), | ||||
| 		} | ||||
| 
 | ||||
| 		err = c.Restore(opts, nil) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("Error:") | ||||
| 			fmt.Print(err) | ||||
| 			fmt.Printf("\n") | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	default: | ||||
| 		fmt.Printf("unknown action\n") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("Success\n") | ||||
| } | ||||
|  | @ -0,0 +1,192 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
| 
 | ||||
| 	"github.com/checkpoint-restore/go-criu" | ||||
| 	"github.com/checkpoint-restore/go-criu/phaul" | ||||
| 	"github.com/checkpoint-restore/go-criu/rpc" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| type testLocal struct { | ||||
| 	criu.NoNotify | ||||
| 	r *testRemote | ||||
| } | ||||
| 
 | ||||
| type testRemote struct { | ||||
| 	srv *phaul.Server | ||||
| } | ||||
| 
 | ||||
| /* Dir where test will put dump images */ | ||||
| const imagesDir = "image" | ||||
| 
 | ||||
| func prepareImages() error { | ||||
| 	err := os.Mkdir(imagesDir, 0700) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	/* Work dir for PhaulClient */ | ||||
| 	err = os.Mkdir(imagesDir+"/local", 0700) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	/* Work dir for PhaulServer */ | ||||
| 	err = os.Mkdir(imagesDir+"/remote", 0700) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	/* Work dir for DumpCopyRestore */ | ||||
| 	err = os.Mkdir(imagesDir+"/test", 0700) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func mergeImages(dumpDir, lastPreDumpDir string) error { | ||||
| 	idir, err := os.Open(dumpDir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	defer idir.Close() | ||||
| 
 | ||||
| 	imgs, err := idir.Readdirnames(0) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, fname := range imgs { | ||||
| 		if !strings.HasSuffix(fname, ".img") { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		fmt.Printf("\t%s -> %s/\n", fname, lastPreDumpDir) | ||||
| 		err = syscall.Link(dumpDir+"/"+fname, lastPreDumpDir+"/"+fname) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (r *testRemote) doRestore() error { | ||||
| 	lastSrvImagesDir := r.srv.LastImagesDir() | ||||
| 	/* | ||||
| 	 * In imagesDir we have images from dump, in the | ||||
| 	 * lastSrvImagesDir -- where server-side images | ||||
| 	 * (from page server, with pages and pagemaps) are. | ||||
| 	 * Need to put former into latter and restore from | ||||
| 	 * them. | ||||
| 	 */ | ||||
| 	err := mergeImages(imagesDir+"/test", lastSrvImagesDir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	imgDir, err := os.Open(lastSrvImagesDir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer imgDir.Close() | ||||
| 
 | ||||
| 	opts := rpc.CriuOpts{ | ||||
| 		LogLevel:    proto.Int32(4), | ||||
| 		LogFile:     proto.String("restore.log"), | ||||
| 		ImagesDirFd: proto.Int32(int32(imgDir.Fd())), | ||||
| 	} | ||||
| 
 | ||||
| 	cr := r.srv.GetCriu() | ||||
| 	fmt.Printf("Do restore\n") | ||||
| 	return cr.Restore(opts, nil) | ||||
| } | ||||
| 
 | ||||
| func (l *testLocal) PostDump() error { | ||||
| 	return l.r.doRestore() | ||||
| } | ||||
| 
 | ||||
| func (l *testLocal) DumpCopyRestore(cr *criu.Criu, cfg phaul.Config, lastClnImagesDir string) error { | ||||
| 	fmt.Printf("Final stage\n") | ||||
| 
 | ||||
| 	imgDir, err := os.Open(imagesDir + "/test") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer imgDir.Close() | ||||
| 
 | ||||
| 	psi := rpc.CriuPageServerInfo{ | ||||
| 		Fd: proto.Int32(int32(cfg.Memfd)), | ||||
| 	} | ||||
| 
 | ||||
| 	opts := rpc.CriuOpts{ | ||||
| 		Pid:         proto.Int32(int32(cfg.Pid)), | ||||
| 		LogLevel:    proto.Int32(4), | ||||
| 		LogFile:     proto.String("dump.log"), | ||||
| 		ImagesDirFd: proto.Int32(int32(imgDir.Fd())), | ||||
| 		TrackMem:    proto.Bool(true), | ||||
| 		ParentImg:   proto.String(lastClnImagesDir), | ||||
| 		Ps:          &psi, | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("Do dump\n") | ||||
| 	return cr.Dump(opts, l) | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	pid, _ := strconv.Atoi(os.Args[1]) | ||||
| 	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Can't make socketpair: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	err = prepareImages() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Can't prepare dirs for images: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("Make server part (socket %d)\n", fds[1]) | ||||
| 	srv, err := phaul.MakePhaulServer(phaul.Config{ | ||||
| 		Pid:   pid, | ||||
| 		Memfd: fds[1], | ||||
| 		Wdir:  imagesDir + "/remote"}) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Unable to run a server: %v", err) | ||||
| 		os.Exit(1) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	r := &testRemote{srv} | ||||
| 
 | ||||
| 	fmt.Printf("Make client part (socket %d)\n", fds[0]) | ||||
| 	cln, err := phaul.MakePhaulClient(&testLocal{r: r}, srv, | ||||
| 		phaul.Config{ | ||||
| 			Pid:   pid, | ||||
| 			Memfd: fds[0], | ||||
| 			Wdir:  imagesDir + "/local"}) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Unable to run a client: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("Migrate\n") | ||||
| 	err = cln.Migrate() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Failed: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("SUCCESS!\n") | ||||
| } | ||||
|  | @ -0,0 +1,57 @@ | |||
| #define _GNU_SOURCE | ||||
| #include <stdio.h> | ||||
| #include <signal.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/mman.h> | ||||
| #include <fcntl.h> | ||||
| #include <sched.h> | ||||
| 
 | ||||
| #define STKS	(4*4096) | ||||
| 
 | ||||
| #ifndef CLONE_NEWPID | ||||
| #define CLONE_NEWPID    0x20000000 | ||||
| #endif | ||||
| 
 | ||||
| static int do_test(void *logf) | ||||
| { | ||||
| 	int fd, i = 0; | ||||
| 
 | ||||
| 	setsid(); | ||||
| 
 | ||||
| 	close(0); | ||||
| 	close(1); | ||||
| 	close(2); | ||||
| 
 | ||||
| 	fd = open("/dev/null", O_RDONLY); | ||||
| 	if (fd != 0) { | ||||
| 		dup2(fd, 0); | ||||
| 		close(fd); | ||||
| 	} | ||||
| 
 | ||||
| 	fd = open(logf, O_WRONLY | O_TRUNC | O_CREAT, 0600); | ||||
| 	dup2(fd, 1); | ||||
| 	dup2(fd, 2); | ||||
| 	if (fd != 1 && fd != 2) | ||||
| 		close(fd); | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		sleep(1); | ||||
| 		printf("%d\n", i++); | ||||
| 		fflush(stdout); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	int pid; | ||||
| 	void *stk; | ||||
| 
 | ||||
| 	stk = mmap(NULL, STKS, PROT_READ | PROT_WRITE, | ||||
| 			MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, 0, 0); | ||||
| 	pid = clone(do_test, stk + STKS, SIGCHLD | CLONE_NEWPID, argv[1]); | ||||
| 	printf("Child forked, pid %d\n", pid); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -0,0 +1,31 @@ | |||
| Go support for Protocol Buffers - Google's data interchange format | ||||
| 
 | ||||
| Copyright 2010 The Go Authors.  All rights reserved. | ||||
| https://github.com/golang/protobuf | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
| 
 | ||||
|     * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|     * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|     * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| 
 | ||||
|  | @ -0,0 +1,241 @@ | |||
| # Go support for Protocol Buffers | ||||
| 
 | ||||
| Google's data interchange format. | ||||
| Copyright 2010 The Go Authors. | ||||
| https://github.com/golang/protobuf | ||||
| 
 | ||||
| This package and the code it generates requires at least Go 1.4. | ||||
| 
 | ||||
| This software implements Go bindings for protocol buffers.  For | ||||
| information about protocol buffers themselves, see | ||||
| 	https://developers.google.com/protocol-buffers/ | ||||
| 
 | ||||
| ## Installation ## | ||||
| 
 | ||||
| To use this software, you must: | ||||
| - Install the standard C++ implementation of protocol buffers from | ||||
| 	https://developers.google.com/protocol-buffers/ | ||||
| - Of course, install the Go compiler and tools from | ||||
| 	https://golang.org/ | ||||
|   See | ||||
| 	https://golang.org/doc/install | ||||
|   for details or, if you are using gccgo, follow the instructions at | ||||
| 	https://golang.org/doc/install/gccgo | ||||
| - Grab the code from the repository and install the proto package. | ||||
|   The simplest way is to run `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}`. | ||||
|   The compiler plugin, protoc-gen-go, will be installed in $GOBIN, | ||||
|   defaulting to $GOPATH/bin.  It must be in your $PATH for the protocol | ||||
|   compiler, protoc, to find it. | ||||
| 
 | ||||
| This software has two parts: a 'protocol compiler plugin' that | ||||
| generates Go source files that, once compiled, can access and manage | ||||
| protocol buffers; and a library that implements run-time support for | ||||
| encoding (marshaling), decoding (unmarshaling), and accessing protocol | ||||
| buffers. | ||||
| 
 | ||||
| There is support for gRPC in Go using protocol buffers. | ||||
| See the note at the bottom of this file for details. | ||||
| 
 | ||||
| There are no insertion points in the plugin. | ||||
| 
 | ||||
| 
 | ||||
| ## Using protocol buffers with Go ## | ||||
| 
 | ||||
| Once the software is installed, there are two steps to using it. | ||||
| First you must compile the protocol buffer definitions and then import | ||||
| them, with the support library, into your program. | ||||
| 
 | ||||
| To compile the protocol buffer definition, run protoc with the --go_out | ||||
| parameter set to the directory you want to output the Go code to. | ||||
| 
 | ||||
| 	protoc --go_out=. *.proto | ||||
| 
 | ||||
| The generated files will be suffixed .pb.go.  See the Test code below | ||||
| for an example using such a file. | ||||
| 
 | ||||
| 
 | ||||
| The package comment for the proto library contains text describing | ||||
| the interface provided in Go for protocol buffers. Here is an edited | ||||
| version. | ||||
| 
 | ||||
| ========== | ||||
| 
 | ||||
| The proto package converts data structures to and from the | ||||
| wire format of protocol buffers.  It works in concert with the | ||||
| Go source code generated for .proto files by the protocol compiler. | ||||
| 
 | ||||
| A summary of the properties of the protocol buffer interface | ||||
| for a protocol buffer variable v: | ||||
| 
 | ||||
|   - Names are turned from camel_case to CamelCase for export. | ||||
|   - There are no methods on v to set fields; just treat | ||||
|   	them as structure fields. | ||||
|   - There are getters that return a field's value if set, | ||||
| 	and return the field's default value if unset. | ||||
| 	The getters work even if the receiver is a nil message. | ||||
|   - The zero value for a struct is its correct initialization state. | ||||
| 	All desired fields must be set before marshaling. | ||||
|   - A Reset() method will restore a protobuf struct to its zero state. | ||||
|   - Non-repeated fields are pointers to the values; nil means unset. | ||||
| 	That is, optional or required field int32 f becomes F *int32. | ||||
|   - Repeated fields are slices. | ||||
|   - Helper functions are available to aid the setting of fields. | ||||
| 	Helpers for getting values are superseded by the | ||||
| 	GetFoo methods and their use is deprecated. | ||||
| 		msg.Foo = proto.String("hello") // set field | ||||
|   - Constants are defined to hold the default values of all fields that | ||||
| 	have them.  They have the form Default_StructName_FieldName. | ||||
| 	Because the getter methods handle defaulted values, | ||||
| 	direct use of these constants should be rare. | ||||
|   - Enums are given type names and maps from names to values. | ||||
| 	Enum values are prefixed with the enum's type name. Enum types have | ||||
| 	a String method, and a Enum method to assist in message construction. | ||||
|   - Nested groups and enums have type names prefixed with the name of | ||||
|   	the surrounding message type. | ||||
|   - Extensions are given descriptor names that start with E_, | ||||
| 	followed by an underscore-delimited list of the nested messages | ||||
| 	that contain it (if any) followed by the CamelCased name of the | ||||
| 	extension field itself.  HasExtension, ClearExtension, GetExtension | ||||
| 	and SetExtension are functions for manipulating extensions. | ||||
|   - Oneof field sets are given a single field in their message, | ||||
| 	with distinguished wrapper types for each possible field value. | ||||
|   - Marshal and Unmarshal are functions to encode and decode the wire format. | ||||
| 
 | ||||
| When the .proto file specifies `syntax="proto3"`, there are some differences: | ||||
| 
 | ||||
|   - Non-repeated fields of non-message type are values instead of pointers. | ||||
|   - Getters are only generated for message and oneof fields. | ||||
|   - Enum types do not get an Enum method. | ||||
| 
 | ||||
| Consider file test.proto, containing | ||||
| 
 | ||||
| ```proto | ||||
| 	package example; | ||||
| 	 | ||||
| 	enum FOO { X = 17; }; | ||||
| 	 | ||||
| 	message Test { | ||||
| 	  required string label = 1; | ||||
| 	  optional int32 type = 2 [default=77]; | ||||
| 	  repeated int64 reps = 3; | ||||
| 	  optional group OptionalGroup = 4 { | ||||
| 	    required string RequiredField = 5; | ||||
| 	  } | ||||
| 	} | ||||
| ``` | ||||
| 
 | ||||
| To create and play with a Test object from the example package, | ||||
| 
 | ||||
| ```go | ||||
| 	package main | ||||
| 
 | ||||
| 	import ( | ||||
| 		"log" | ||||
| 
 | ||||
| 		"github.com/golang/protobuf/proto" | ||||
| 		"path/to/example" | ||||
| 	) | ||||
| 
 | ||||
| 	func main() { | ||||
| 		test := &example.Test { | ||||
| 			Label: proto.String("hello"), | ||||
| 			Type:  proto.Int32(17), | ||||
| 			Reps:  []int64{1, 2, 3}, | ||||
| 			Optionalgroup: &example.Test_OptionalGroup { | ||||
| 				RequiredField: proto.String("good bye"), | ||||
| 			}, | ||||
| 		} | ||||
| 		data, err := proto.Marshal(test) | ||||
| 		if err != nil { | ||||
| 			log.Fatal("marshaling error: ", err) | ||||
| 		} | ||||
| 		newTest := &example.Test{} | ||||
| 		err = proto.Unmarshal(data, newTest) | ||||
| 		if err != nil { | ||||
| 			log.Fatal("unmarshaling error: ", err) | ||||
| 		} | ||||
| 		// Now test and newTest contain the same data. | ||||
| 		if test.GetLabel() != newTest.GetLabel() { | ||||
| 			log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) | ||||
| 		} | ||||
| 		// etc. | ||||
| 	} | ||||
| ``` | ||||
| 
 | ||||
| ## Parameters ## | ||||
| 
 | ||||
| To pass extra parameters to the plugin, use a comma-separated | ||||
| parameter list separated from the output directory by a colon: | ||||
| 
 | ||||
| 
 | ||||
| 	protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto | ||||
| 
 | ||||
| 
 | ||||
| - `import_prefix=xxx` - a prefix that is added onto the beginning of | ||||
|   all imports. Useful for things like generating protos in a | ||||
|   subdirectory, or regenerating vendored protobufs in-place. | ||||
| - `import_path=foo/bar` - used as the package if no input files | ||||
|   declare `go_package`. If it contains slashes, everything up to the | ||||
|   rightmost slash is ignored. | ||||
| - `plugins=plugin1+plugin2` - specifies the list of sub-plugins to | ||||
|   load. The only plugin in this repo is `grpc`. | ||||
| - `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is | ||||
|   associated with Go package quux/shme.  This is subject to the | ||||
|   import_prefix parameter. | ||||
| 
 | ||||
| ## gRPC Support ## | ||||
| 
 | ||||
| If a proto file specifies RPC services, protoc-gen-go can be instructed to | ||||
| generate code compatible with gRPC (http://www.grpc.io/). To do this, pass | ||||
| the `plugins` parameter to protoc-gen-go; the usual way is to insert it into | ||||
| the --go_out argument to protoc: | ||||
| 
 | ||||
| 	protoc --go_out=plugins=grpc:. *.proto | ||||
| 
 | ||||
| ## Compatibility ## | ||||
| 
 | ||||
| The library and the generated code are expected to be stable over time. | ||||
| However, we reserve the right to make breaking changes without notice for the | ||||
| following reasons: | ||||
| 
 | ||||
| - Security. A security issue in the specification or implementation may come to | ||||
|   light whose resolution requires breaking compatibility. We reserve the right | ||||
|   to address such security issues. | ||||
| - Unspecified behavior.  There are some aspects of the Protocol Buffers | ||||
|   specification that are undefined.  Programs that depend on such unspecified | ||||
|   behavior may break in future releases. | ||||
| - Specification errors or changes. If it becomes necessary to address an | ||||
|   inconsistency, incompleteness, or change in the Protocol Buffers | ||||
|   specification, resolving the issue could affect the meaning or legality of | ||||
|   existing programs.  We reserve the right to address such issues, including | ||||
|   updating the implementations. | ||||
| - Bugs.  If the library has a bug that violates the specification, a program | ||||
|   that depends on the buggy behavior may break if the bug is fixed.  We reserve | ||||
|   the right to fix such bugs. | ||||
| - Adding methods or fields to generated structs.  These may conflict with field | ||||
|   names that already exist in a schema, causing applications to break.  When the | ||||
|   code generator encounters a field in the schema that would collide with a | ||||
|   generated field or method name, the code generator will append an underscore | ||||
|   to the generated field or method name. | ||||
| - Adding, removing, or changing methods or fields in generated structs that | ||||
|   start with `XXX`.  These parts of the generated code are exported out of | ||||
|   necessity, but should not be considered part of the public API. | ||||
| - Adding, removing, or changing unexported symbols in generated code. | ||||
| 
 | ||||
| Any breaking changes outside of these will be announced 6 months in advance to | ||||
| protobuf@googlegroups.com. | ||||
| 
 | ||||
| You should, whenever possible, use generated code created by the `protoc-gen-go` | ||||
| tool built at the same commit as the `proto` package.  The `proto` package | ||||
| declares package-level constants in the form `ProtoPackageIsVersionX`. | ||||
| Application code and generated code may depend on one of these constants to | ||||
| ensure that compilation will fail if the available version of the proto library | ||||
| is too old.  Whenever we make a change to the generated code that requires newer | ||||
| library support, in the same commit we will increment the version number of the | ||||
| generated code and declare a new package-level constant whose name incorporates | ||||
| the latest version number.  Removing a compatibility constant is considered a | ||||
| breaking change and would be subject to the announcement policy stated above. | ||||
| 
 | ||||
| The `protoc-gen-go/generator` package exposes a plugin interface, | ||||
| which is used by the gRPC code generation. This interface is not | ||||
| supported and is subject to incompatible changes without notice. | ||||
|  | @ -0,0 +1,229 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2011 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| // Protocol buffer deep copy and merge.
 | ||||
| // TODO: RawMessage.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // Clone returns a deep copy of a protocol buffer.
 | ||||
| func Clone(pb Message) Message { | ||||
| 	in := reflect.ValueOf(pb) | ||||
| 	if in.IsNil() { | ||||
| 		return pb | ||||
| 	} | ||||
| 
 | ||||
| 	out := reflect.New(in.Type().Elem()) | ||||
| 	// out is empty so a merge is a deep copy.
 | ||||
| 	mergeStruct(out.Elem(), in.Elem()) | ||||
| 	return out.Interface().(Message) | ||||
| } | ||||
| 
 | ||||
| // Merge merges src into dst.
 | ||||
| // Required and optional fields that are set in src will be set to that value in dst.
 | ||||
| // Elements of repeated fields will be appended.
 | ||||
| // Merge panics if src and dst are not the same type, or if dst is nil.
 | ||||
| func Merge(dst, src Message) { | ||||
| 	in := reflect.ValueOf(src) | ||||
| 	out := reflect.ValueOf(dst) | ||||
| 	if out.IsNil() { | ||||
| 		panic("proto: nil destination") | ||||
| 	} | ||||
| 	if in.Type() != out.Type() { | ||||
| 		// Explicit test prior to mergeStruct so that mistyped nils will fail
 | ||||
| 		panic("proto: type mismatch") | ||||
| 	} | ||||
| 	if in.IsNil() { | ||||
| 		// Merging nil into non-nil is a quiet no-op
 | ||||
| 		return | ||||
| 	} | ||||
| 	mergeStruct(out.Elem(), in.Elem()) | ||||
| } | ||||
| 
 | ||||
| func mergeStruct(out, in reflect.Value) { | ||||
| 	sprop := GetProperties(in.Type()) | ||||
| 	for i := 0; i < in.NumField(); i++ { | ||||
| 		f := in.Type().Field(i) | ||||
| 		if strings.HasPrefix(f.Name, "XXX_") { | ||||
| 			continue | ||||
| 		} | ||||
| 		mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) | ||||
| 	} | ||||
| 
 | ||||
| 	if emIn, ok := extendable(in.Addr().Interface()); ok { | ||||
| 		emOut, _ := extendable(out.Addr().Interface()) | ||||
| 		mIn, muIn := emIn.extensionsRead() | ||||
| 		if mIn != nil { | ||||
| 			mOut := emOut.extensionsWrite() | ||||
| 			muIn.Lock() | ||||
| 			mergeExtension(mOut, mIn) | ||||
| 			muIn.Unlock() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	uf := in.FieldByName("XXX_unrecognized") | ||||
| 	if !uf.IsValid() { | ||||
| 		return | ||||
| 	} | ||||
| 	uin := uf.Bytes() | ||||
| 	if len(uin) > 0 { | ||||
| 		out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // mergeAny performs a merge between two values of the same type.
 | ||||
| // viaPtr indicates whether the values were indirected through a pointer (implying proto2).
 | ||||
| // prop is set if this is a struct field (it may be nil).
 | ||||
| func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { | ||||
| 	if in.Type() == protoMessageType { | ||||
| 		if !in.IsNil() { | ||||
| 			if out.IsNil() { | ||||
| 				out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) | ||||
| 			} else { | ||||
| 				Merge(out.Interface().(Message), in.Interface().(Message)) | ||||
| 			} | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	switch in.Kind() { | ||||
| 	case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, | ||||
| 		reflect.String, reflect.Uint32, reflect.Uint64: | ||||
| 		if !viaPtr && isProto3Zero(in) { | ||||
| 			return | ||||
| 		} | ||||
| 		out.Set(in) | ||||
| 	case reflect.Interface: | ||||
| 		// Probably a oneof field; copy non-nil values.
 | ||||
| 		if in.IsNil() { | ||||
| 			return | ||||
| 		} | ||||
| 		// Allocate destination if it is not set, or set to a different type.
 | ||||
| 		// Otherwise we will merge as normal.
 | ||||
| 		if out.IsNil() || out.Elem().Type() != in.Elem().Type() { | ||||
| 			out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
 | ||||
| 		} | ||||
| 		mergeAny(out.Elem(), in.Elem(), false, nil) | ||||
| 	case reflect.Map: | ||||
| 		if in.Len() == 0 { | ||||
| 			return | ||||
| 		} | ||||
| 		if out.IsNil() { | ||||
| 			out.Set(reflect.MakeMap(in.Type())) | ||||
| 		} | ||||
| 		// For maps with value types of *T or []byte we need to deep copy each value.
 | ||||
| 		elemKind := in.Type().Elem().Kind() | ||||
| 		for _, key := range in.MapKeys() { | ||||
| 			var val reflect.Value | ||||
| 			switch elemKind { | ||||
| 			case reflect.Ptr: | ||||
| 				val = reflect.New(in.Type().Elem().Elem()) | ||||
| 				mergeAny(val, in.MapIndex(key), false, nil) | ||||
| 			case reflect.Slice: | ||||
| 				val = in.MapIndex(key) | ||||
| 				val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) | ||||
| 			default: | ||||
| 				val = in.MapIndex(key) | ||||
| 			} | ||||
| 			out.SetMapIndex(key, val) | ||||
| 		} | ||||
| 	case reflect.Ptr: | ||||
| 		if in.IsNil() { | ||||
| 			return | ||||
| 		} | ||||
| 		if out.IsNil() { | ||||
| 			out.Set(reflect.New(in.Elem().Type())) | ||||
| 		} | ||||
| 		mergeAny(out.Elem(), in.Elem(), true, nil) | ||||
| 	case reflect.Slice: | ||||
| 		if in.IsNil() { | ||||
| 			return | ||||
| 		} | ||||
| 		if in.Type().Elem().Kind() == reflect.Uint8 { | ||||
| 			// []byte is a scalar bytes field, not a repeated field.
 | ||||
| 
 | ||||
| 			// Edge case: if this is in a proto3 message, a zero length
 | ||||
| 			// bytes field is considered the zero value, and should not
 | ||||
| 			// be merged.
 | ||||
| 			if prop != nil && prop.proto3 && in.Len() == 0 { | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			// Make a deep copy.
 | ||||
| 			// Append to []byte{} instead of []byte(nil) so that we never end up
 | ||||
| 			// with a nil result.
 | ||||
| 			out.SetBytes(append([]byte{}, in.Bytes()...)) | ||||
| 			return | ||||
| 		} | ||||
| 		n := in.Len() | ||||
| 		if out.IsNil() { | ||||
| 			out.Set(reflect.MakeSlice(in.Type(), 0, n)) | ||||
| 		} | ||||
| 		switch in.Type().Elem().Kind() { | ||||
| 		case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, | ||||
| 			reflect.String, reflect.Uint32, reflect.Uint64: | ||||
| 			out.Set(reflect.AppendSlice(out, in)) | ||||
| 		default: | ||||
| 			for i := 0; i < n; i++ { | ||||
| 				x := reflect.Indirect(reflect.New(in.Type().Elem())) | ||||
| 				mergeAny(x, in.Index(i), false, nil) | ||||
| 				out.Set(reflect.Append(out, x)) | ||||
| 			} | ||||
| 		} | ||||
| 	case reflect.Struct: | ||||
| 		mergeStruct(out, in) | ||||
| 	default: | ||||
| 		// unknown type, so not a protocol buffer
 | ||||
| 		log.Printf("proto: don't know how to copy %v", in) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func mergeExtension(out, in map[int32]Extension) { | ||||
| 	for extNum, eIn := range in { | ||||
| 		eOut := Extension{desc: eIn.desc} | ||||
| 		if eIn.value != nil { | ||||
| 			v := reflect.New(reflect.TypeOf(eIn.value)).Elem() | ||||
| 			mergeAny(v, reflect.ValueOf(eIn.value), false, nil) | ||||
| 			eOut.value = v.Interface() | ||||
| 		} | ||||
| 		if eIn.enc != nil { | ||||
| 			eOut.enc = make([]byte, len(eIn.enc)) | ||||
| 			copy(eOut.enc, eIn.enc) | ||||
| 		} | ||||
| 
 | ||||
| 		out[extNum] = eOut | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,970 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| /* | ||||
|  * Routines for decoding protocol buffer data to construct in-memory representations. | ||||
|  */ | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| ) | ||||
| 
 | ||||
| // errOverflow is returned when an integer is too large to be represented.
 | ||||
| var errOverflow = errors.New("proto: integer overflow") | ||||
| 
 | ||||
| // ErrInternalBadWireType is returned by generated code when an incorrect
 | ||||
| // wire type is encountered. It does not get returned to user code.
 | ||||
| var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") | ||||
| 
 | ||||
| // The fundamental decoders that interpret bytes on the wire.
 | ||||
| // Those that take integer types all return uint64 and are
 | ||||
| // therefore of type valueDecoder.
 | ||||
| 
 | ||||
| // DecodeVarint reads a varint-encoded integer from the slice.
 | ||||
| // It returns the integer and the number of bytes consumed, or
 | ||||
| // zero if there is not enough.
 | ||||
| // This is the format for the
 | ||||
| // int32, int64, uint32, uint64, bool, and enum
 | ||||
| // protocol buffer types.
 | ||||
| func DecodeVarint(buf []byte) (x uint64, n int) { | ||||
| 	for shift := uint(0); shift < 64; shift += 7 { | ||||
| 		if n >= len(buf) { | ||||
| 			return 0, 0 | ||||
| 		} | ||||
| 		b := uint64(buf[n]) | ||||
| 		n++ | ||||
| 		x |= (b & 0x7F) << shift | ||||
| 		if (b & 0x80) == 0 { | ||||
| 			return x, n | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// The number is too large to represent in a 64-bit value.
 | ||||
| 	return 0, 0 | ||||
| } | ||||
| 
 | ||||
| func (p *Buffer) decodeVarintSlow() (x uint64, err error) { | ||||
| 	i := p.index | ||||
| 	l := len(p.buf) | ||||
| 
 | ||||
| 	for shift := uint(0); shift < 64; shift += 7 { | ||||
| 		if i >= l { | ||||
| 			err = io.ErrUnexpectedEOF | ||||
| 			return | ||||
| 		} | ||||
| 		b := p.buf[i] | ||||
| 		i++ | ||||
| 		x |= (uint64(b) & 0x7F) << shift | ||||
| 		if b < 0x80 { | ||||
| 			p.index = i | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// The number is too large to represent in a 64-bit value.
 | ||||
| 	err = errOverflow | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DecodeVarint reads a varint-encoded integer from the Buffer.
 | ||||
| // This is the format for the
 | ||||
| // int32, int64, uint32, uint64, bool, and enum
 | ||||
| // protocol buffer types.
 | ||||
| func (p *Buffer) DecodeVarint() (x uint64, err error) { | ||||
| 	i := p.index | ||||
| 	buf := p.buf | ||||
| 
 | ||||
| 	if i >= len(buf) { | ||||
| 		return 0, io.ErrUnexpectedEOF | ||||
| 	} else if buf[i] < 0x80 { | ||||
| 		p.index++ | ||||
| 		return uint64(buf[i]), nil | ||||
| 	} else if len(buf)-i < 10 { | ||||
| 		return p.decodeVarintSlow() | ||||
| 	} | ||||
| 
 | ||||
| 	var b uint64 | ||||
| 	// we already checked the first byte
 | ||||
| 	x = uint64(buf[i]) - 0x80 | ||||
| 	i++ | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 7 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 7 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 14 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 14 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 21 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 21 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 28 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 28 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 35 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 35 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 42 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 42 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 49 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 49 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 56 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	x -= 0x80 << 56 | ||||
| 
 | ||||
| 	b = uint64(buf[i]) | ||||
| 	i++ | ||||
| 	x += b << 63 | ||||
| 	if b&0x80 == 0 { | ||||
| 		goto done | ||||
| 	} | ||||
| 	// x -= 0x80 << 63 // Always zero.
 | ||||
| 
 | ||||
| 	return 0, errOverflow | ||||
| 
 | ||||
| done: | ||||
| 	p.index = i | ||||
| 	return x, nil | ||||
| } | ||||
| 
 | ||||
| // DecodeFixed64 reads a 64-bit integer from the Buffer.
 | ||||
| // This is the format for the
 | ||||
| // fixed64, sfixed64, and double protocol buffer types.
 | ||||
| func (p *Buffer) DecodeFixed64() (x uint64, err error) { | ||||
| 	// x, err already 0
 | ||||
| 	i := p.index + 8 | ||||
| 	if i < 0 || i > len(p.buf) { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 		return | ||||
| 	} | ||||
| 	p.index = i | ||||
| 
 | ||||
| 	x = uint64(p.buf[i-8]) | ||||
| 	x |= uint64(p.buf[i-7]) << 8 | ||||
| 	x |= uint64(p.buf[i-6]) << 16 | ||||
| 	x |= uint64(p.buf[i-5]) << 24 | ||||
| 	x |= uint64(p.buf[i-4]) << 32 | ||||
| 	x |= uint64(p.buf[i-3]) << 40 | ||||
| 	x |= uint64(p.buf[i-2]) << 48 | ||||
| 	x |= uint64(p.buf[i-1]) << 56 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DecodeFixed32 reads a 32-bit integer from the Buffer.
 | ||||
| // This is the format for the
 | ||||
| // fixed32, sfixed32, and float protocol buffer types.
 | ||||
| func (p *Buffer) DecodeFixed32() (x uint64, err error) { | ||||
| 	// x, err already 0
 | ||||
| 	i := p.index + 4 | ||||
| 	if i < 0 || i > len(p.buf) { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 		return | ||||
| 	} | ||||
| 	p.index = i | ||||
| 
 | ||||
| 	x = uint64(p.buf[i-4]) | ||||
| 	x |= uint64(p.buf[i-3]) << 8 | ||||
| 	x |= uint64(p.buf[i-2]) << 16 | ||||
| 	x |= uint64(p.buf[i-1]) << 24 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DecodeZigzag64 reads a zigzag-encoded 64-bit integer
 | ||||
| // from the Buffer.
 | ||||
| // This is the format used for the sint64 protocol buffer type.
 | ||||
| func (p *Buffer) DecodeZigzag64() (x uint64, err error) { | ||||
| 	x, err = p.DecodeVarint() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DecodeZigzag32 reads a zigzag-encoded 32-bit integer
 | ||||
| // from  the Buffer.
 | ||||
| // This is the format used for the sint32 protocol buffer type.
 | ||||
| func (p *Buffer) DecodeZigzag32() (x uint64, err error) { | ||||
| 	x, err = p.DecodeVarint() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // These are not ValueDecoders: they produce an array of bytes or a string.
 | ||||
| // bytes, embedded messages
 | ||||
| 
 | ||||
| // DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
 | ||||
| // This is the format used for the bytes protocol buffer
 | ||||
| // type and for embedded messages.
 | ||||
| func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { | ||||
| 	n, err := p.DecodeVarint() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	nb := int(n) | ||||
| 	if nb < 0 { | ||||
| 		return nil, fmt.Errorf("proto: bad byte length %d", nb) | ||||
| 	} | ||||
| 	end := p.index + nb | ||||
| 	if end < p.index || end > len(p.buf) { | ||||
| 		return nil, io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 
 | ||||
| 	if !alloc { | ||||
| 		// todo: check if can get more uses of alloc=false
 | ||||
| 		buf = p.buf[p.index:end] | ||||
| 		p.index += nb | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	buf = make([]byte, nb) | ||||
| 	copy(buf, p.buf[p.index:]) | ||||
| 	p.index += nb | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DecodeStringBytes reads an encoded string from the Buffer.
 | ||||
| // This is the format used for the proto2 string type.
 | ||||
| func (p *Buffer) DecodeStringBytes() (s string, err error) { | ||||
| 	buf, err := p.DecodeRawBytes(false) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return string(buf), nil | ||||
| } | ||||
| 
 | ||||
| // Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
 | ||||
| // If the protocol buffer has extensions, and the field matches, add it as an extension.
 | ||||
| // Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
 | ||||
| func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { | ||||
| 	oi := o.index | ||||
| 
 | ||||
| 	err := o.skip(t, tag, wire) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if !unrecField.IsValid() { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	ptr := structPointer_Bytes(base, unrecField) | ||||
| 
 | ||||
| 	// Add the skipped field to struct field
 | ||||
| 	obuf := o.buf | ||||
| 
 | ||||
| 	o.buf = *ptr | ||||
| 	o.EncodeVarint(uint64(tag<<3 | wire)) | ||||
| 	*ptr = append(o.buf, obuf[oi:o.index]...) | ||||
| 
 | ||||
| 	o.buf = obuf | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
 | ||||
| func (o *Buffer) skip(t reflect.Type, tag, wire int) error { | ||||
| 
 | ||||
| 	var u uint64 | ||||
| 	var err error | ||||
| 
 | ||||
| 	switch wire { | ||||
| 	case WireVarint: | ||||
| 		_, err = o.DecodeVarint() | ||||
| 	case WireFixed64: | ||||
| 		_, err = o.DecodeFixed64() | ||||
| 	case WireBytes: | ||||
| 		_, err = o.DecodeRawBytes(false) | ||||
| 	case WireFixed32: | ||||
| 		_, err = o.DecodeFixed32() | ||||
| 	case WireStartGroup: | ||||
| 		for { | ||||
| 			u, err = o.DecodeVarint() | ||||
| 			if err != nil { | ||||
| 				break | ||||
| 			} | ||||
| 			fwire := int(u & 0x7) | ||||
| 			if fwire == WireEndGroup { | ||||
| 				break | ||||
| 			} | ||||
| 			ftag := int(u >> 3) | ||||
| 			err = o.skip(t, ftag, fwire) | ||||
| 			if err != nil { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Unmarshaler is the interface representing objects that can
 | ||||
| // unmarshal themselves.  The method should reset the receiver before
 | ||||
| // decoding starts.  The argument points to data that may be
 | ||||
| // overwritten, so implementations should not keep references to the
 | ||||
| // buffer.
 | ||||
| type Unmarshaler interface { | ||||
| 	Unmarshal([]byte) error | ||||
| } | ||||
| 
 | ||||
| // Unmarshal parses the protocol buffer representation in buf and places the
 | ||||
| // decoded result in pb.  If the struct underlying pb does not match
 | ||||
| // the data in buf, the results can be unpredictable.
 | ||||
| //
 | ||||
| // Unmarshal resets pb before starting to unmarshal, so any
 | ||||
| // existing data in pb is always removed. Use UnmarshalMerge
 | ||||
| // to preserve and append to existing data.
 | ||||
| func Unmarshal(buf []byte, pb Message) error { | ||||
| 	pb.Reset() | ||||
| 	return UnmarshalMerge(buf, pb) | ||||
| } | ||||
| 
 | ||||
| // UnmarshalMerge parses the protocol buffer representation in buf and
 | ||||
| // writes the decoded result to pb.  If the struct underlying pb does not match
 | ||||
| // the data in buf, the results can be unpredictable.
 | ||||
| //
 | ||||
| // UnmarshalMerge merges into existing data in pb.
 | ||||
| // Most code should use Unmarshal instead.
 | ||||
| func UnmarshalMerge(buf []byte, pb Message) error { | ||||
| 	// If the object can unmarshal itself, let it.
 | ||||
| 	if u, ok := pb.(Unmarshaler); ok { | ||||
| 		return u.Unmarshal(buf) | ||||
| 	} | ||||
| 	return NewBuffer(buf).Unmarshal(pb) | ||||
| } | ||||
| 
 | ||||
| // DecodeMessage reads a count-delimited message from the Buffer.
 | ||||
| func (p *Buffer) DecodeMessage(pb Message) error { | ||||
| 	enc, err := p.DecodeRawBytes(false) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return NewBuffer(enc).Unmarshal(pb) | ||||
| } | ||||
| 
 | ||||
| // DecodeGroup reads a tag-delimited group from the Buffer.
 | ||||
| func (p *Buffer) DecodeGroup(pb Message) error { | ||||
| 	typ, base, err := getbase(pb) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) | ||||
| } | ||||
| 
 | ||||
| // Unmarshal parses the protocol buffer representation in the
 | ||||
| // Buffer and places the decoded result in pb.  If the struct
 | ||||
| // underlying pb does not match the data in the buffer, the results can be
 | ||||
| // unpredictable.
 | ||||
| //
 | ||||
| // Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
 | ||||
| func (p *Buffer) Unmarshal(pb Message) error { | ||||
| 	// If the object can unmarshal itself, let it.
 | ||||
| 	if u, ok := pb.(Unmarshaler); ok { | ||||
| 		err := u.Unmarshal(p.buf[p.index:]) | ||||
| 		p.index = len(p.buf) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	typ, base, err := getbase(pb) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) | ||||
| 
 | ||||
| 	if collectStats { | ||||
| 		stats.Decode++ | ||||
| 	} | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // unmarshalType does the work of unmarshaling a structure.
 | ||||
| func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { | ||||
| 	var state errorState | ||||
| 	required, reqFields := prop.reqCount, uint64(0) | ||||
| 
 | ||||
| 	var err error | ||||
| 	for err == nil && o.index < len(o.buf) { | ||||
| 		oi := o.index | ||||
| 		var u uint64 | ||||
| 		u, err = o.DecodeVarint() | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		wire := int(u & 0x7) | ||||
| 		if wire == WireEndGroup { | ||||
| 			if is_group { | ||||
| 				if required > 0 { | ||||
| 					// Not enough information to determine the exact field.
 | ||||
| 					// (See below.)
 | ||||
| 					return &RequiredNotSetError{"{Unknown}"} | ||||
| 				} | ||||
| 				return nil // input is satisfied
 | ||||
| 			} | ||||
| 			return fmt.Errorf("proto: %s: wiretype end group for non-group", st) | ||||
| 		} | ||||
| 		tag := int(u >> 3) | ||||
| 		if tag <= 0 { | ||||
| 			return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) | ||||
| 		} | ||||
| 		fieldnum, ok := prop.decoderTags.get(tag) | ||||
| 		if !ok { | ||||
| 			// Maybe it's an extension?
 | ||||
| 			if prop.extendable { | ||||
| 				if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { | ||||
| 					if err = o.skip(st, tag, wire); err == nil { | ||||
| 						extmap := e.extensionsWrite() | ||||
| 						ext := extmap[int32(tag)] // may be missing
 | ||||
| 						ext.enc = append(ext.enc, o.buf[oi:o.index]...) | ||||
| 						extmap[int32(tag)] = ext | ||||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 			// Maybe it's a oneof?
 | ||||
| 			if prop.oneofUnmarshaler != nil { | ||||
| 				m := structPointer_Interface(base, st).(Message) | ||||
| 				// First return value indicates whether tag is a oneof field.
 | ||||
| 				ok, err = prop.oneofUnmarshaler(m, tag, wire, o) | ||||
| 				if err == ErrInternalBadWireType { | ||||
| 					// Map the error to something more descriptive.
 | ||||
| 					// Do the formatting here to save generated code space.
 | ||||
| 					err = fmt.Errorf("bad wiretype for oneof field in %T", m) | ||||
| 				} | ||||
| 				if ok { | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 			err = o.skipAndSave(st, tag, wire, base, prop.unrecField) | ||||
| 			continue | ||||
| 		} | ||||
| 		p := prop.Prop[fieldnum] | ||||
| 
 | ||||
| 		if p.dec == nil { | ||||
| 			fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) | ||||
| 			continue | ||||
| 		} | ||||
| 		dec := p.dec | ||||
| 		if wire != WireStartGroup && wire != p.WireType { | ||||
| 			if wire == WireBytes && p.packedDec != nil { | ||||
| 				// a packable field
 | ||||
| 				dec = p.packedDec | ||||
| 			} else { | ||||
| 				err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		decErr := dec(o, p, base) | ||||
| 		if decErr != nil && !state.shouldContinue(decErr, p) { | ||||
| 			err = decErr | ||||
| 		} | ||||
| 		if err == nil && p.Required { | ||||
| 			// Successfully decoded a required field.
 | ||||
| 			if tag <= 64 { | ||||
| 				// use bitmap for fields 1-64 to catch field reuse.
 | ||||
| 				var mask uint64 = 1 << uint64(tag-1) | ||||
| 				if reqFields&mask == 0 { | ||||
| 					// new required field
 | ||||
| 					reqFields |= mask | ||||
| 					required-- | ||||
| 				} | ||||
| 			} else { | ||||
| 				// This is imprecise. It can be fooled by a required field
 | ||||
| 				// with a tag > 64 that is encoded twice; that's very rare.
 | ||||
| 				// A fully correct implementation would require allocating
 | ||||
| 				// a data structure, which we would like to avoid.
 | ||||
| 				required-- | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if err == nil { | ||||
| 		if is_group { | ||||
| 			return io.ErrUnexpectedEOF | ||||
| 		} | ||||
| 		if state.err != nil { | ||||
| 			return state.err | ||||
| 		} | ||||
| 		if required > 0 { | ||||
| 			// Not enough information to determine the exact field. If we use extra
 | ||||
| 			// CPU, we could determine the field only if the missing required field
 | ||||
| 			// has a tag <= 64 and we check reqFields.
 | ||||
| 			return &RequiredNotSetError{"{Unknown}"} | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Individual type decoders
 | ||||
| // For each,
 | ||||
| //	u is the decoded value,
 | ||||
| //	v is a pointer to the field (pointer) in the struct
 | ||||
| 
 | ||||
| // Sizes of the pools to allocate inside the Buffer.
 | ||||
| // The goal is modest amortization and allocation
 | ||||
| // on at least 16-byte boundaries.
 | ||||
| const ( | ||||
| 	boolPoolSize   = 16 | ||||
| 	uint32PoolSize = 8 | ||||
| 	uint64PoolSize = 4 | ||||
| ) | ||||
| 
 | ||||
| // Decode a bool.
 | ||||
| func (o *Buffer) dec_bool(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(o.bools) == 0 { | ||||
| 		o.bools = make([]bool, boolPoolSize) | ||||
| 	} | ||||
| 	o.bools[0] = u != 0 | ||||
| 	*structPointer_Bool(base, p.field) = &o.bools[0] | ||||
| 	o.bools = o.bools[1:] | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*structPointer_BoolVal(base, p.field) = u != 0 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode an int32.
 | ||||
| func (o *Buffer) dec_int32(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode an int64.
 | ||||
| func (o *Buffer) dec_int64(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	word64_Set(structPointer_Word64(base, p.field), o, u) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	word64Val_Set(structPointer_Word64Val(base, p.field), o, u) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a string.
 | ||||
| func (o *Buffer) dec_string(p *Properties, base structPointer) error { | ||||
| 	s, err := o.DecodeStringBytes() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*structPointer_String(base, p.field) = &s | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { | ||||
| 	s, err := o.DecodeStringBytes() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*structPointer_StringVal(base, p.field) = s | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of bytes ([]byte).
 | ||||
| func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { | ||||
| 	b, err := o.DecodeRawBytes(true) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*structPointer_Bytes(base, p.field) = b | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of bools ([]bool).
 | ||||
| func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	v := structPointer_BoolSlice(base, p.field) | ||||
| 	*v = append(*v, u != 0) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of bools ([]bool) in packed format.
 | ||||
| func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { | ||||
| 	v := structPointer_BoolSlice(base, p.field) | ||||
| 
 | ||||
| 	nn, err := o.DecodeVarint() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	nb := int(nn) // number of bytes of encoded bools
 | ||||
| 	fin := o.index + nb | ||||
| 	if fin < o.index { | ||||
| 		return errOverflow | ||||
| 	} | ||||
| 
 | ||||
| 	y := *v | ||||
| 	for o.index < fin { | ||||
| 		u, err := p.valDec(o) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		y = append(y, u != 0) | ||||
| 	} | ||||
| 
 | ||||
| 	*v = y | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of int32s ([]int32).
 | ||||
| func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	structPointer_Word32Slice(base, p.field).Append(uint32(u)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of int32s ([]int32) in packed format.
 | ||||
| func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { | ||||
| 	v := structPointer_Word32Slice(base, p.field) | ||||
| 
 | ||||
| 	nn, err := o.DecodeVarint() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	nb := int(nn) // number of bytes of encoded int32s
 | ||||
| 
 | ||||
| 	fin := o.index + nb | ||||
| 	if fin < o.index { | ||||
| 		return errOverflow | ||||
| 	} | ||||
| 	for o.index < fin { | ||||
| 		u, err := p.valDec(o) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		v.Append(uint32(u)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of int64s ([]int64).
 | ||||
| func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { | ||||
| 	u, err := p.valDec(o) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	structPointer_Word64Slice(base, p.field).Append(u) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of int64s ([]int64) in packed format.
 | ||||
| func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { | ||||
| 	v := structPointer_Word64Slice(base, p.field) | ||||
| 
 | ||||
| 	nn, err := o.DecodeVarint() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	nb := int(nn) // number of bytes of encoded int64s
 | ||||
| 
 | ||||
| 	fin := o.index + nb | ||||
| 	if fin < o.index { | ||||
| 		return errOverflow | ||||
| 	} | ||||
| 	for o.index < fin { | ||||
| 		u, err := p.valDec(o) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		v.Append(u) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of strings ([]string).
 | ||||
| func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { | ||||
| 	s, err := o.DecodeStringBytes() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	v := structPointer_StringSlice(base, p.field) | ||||
| 	*v = append(*v, s) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of slice of bytes ([][]byte).
 | ||||
| func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { | ||||
| 	b, err := o.DecodeRawBytes(true) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	v := structPointer_BytesSlice(base, p.field) | ||||
| 	*v = append(*v, b) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a map field.
 | ||||
| func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { | ||||
| 	raw, err := o.DecodeRawBytes(false) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	oi := o.index       // index at the end of this map entry
 | ||||
| 	o.index -= len(raw) // move buffer back to start of map entry
 | ||||
| 
 | ||||
| 	mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V
 | ||||
| 	if mptr.Elem().IsNil() { | ||||
| 		mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) | ||||
| 	} | ||||
| 	v := mptr.Elem() // map[K]V
 | ||||
| 
 | ||||
| 	// Prepare addressable doubly-indirect placeholders for the key and value types.
 | ||||
| 	// See enc_new_map for why.
 | ||||
| 	keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K
 | ||||
| 	keybase := toStructPointer(keyptr.Addr())                  // **K
 | ||||
| 
 | ||||
| 	var valbase structPointer | ||||
| 	var valptr reflect.Value | ||||
| 	switch p.mtype.Elem().Kind() { | ||||
| 	case reflect.Slice: | ||||
| 		// []byte
 | ||||
| 		var dummy []byte | ||||
| 		valptr = reflect.ValueOf(&dummy)  // *[]byte
 | ||||
| 		valbase = toStructPointer(valptr) // *[]byte
 | ||||
| 	case reflect.Ptr: | ||||
| 		// message; valptr is **Msg; need to allocate the intermediate pointer
 | ||||
| 		valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
 | ||||
| 		valptr.Set(reflect.New(valptr.Type().Elem())) | ||||
| 		valbase = toStructPointer(valptr) | ||||
| 	default: | ||||
| 		// everything else
 | ||||
| 		valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
 | ||||
| 		valbase = toStructPointer(valptr.Addr())                   // **V
 | ||||
| 	} | ||||
| 
 | ||||
| 	// Decode.
 | ||||
| 	// This parses a restricted wire format, namely the encoding of a message
 | ||||
| 	// with two fields. See enc_new_map for the format.
 | ||||
| 	for o.index < oi { | ||||
| 		// tagcode for key and value properties are always a single byte
 | ||||
| 		// because they have tags 1 and 2.
 | ||||
| 		tagcode := o.buf[o.index] | ||||
| 		o.index++ | ||||
| 		switch tagcode { | ||||
| 		case p.mkeyprop.tagcode[0]: | ||||
| 			if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		case p.mvalprop.tagcode[0]: | ||||
| 			if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		default: | ||||
| 			// TODO: Should we silently skip this instead?
 | ||||
| 			return fmt.Errorf("proto: bad map data tag %d", raw[0]) | ||||
| 		} | ||||
| 	} | ||||
| 	keyelem, valelem := keyptr.Elem(), valptr.Elem() | ||||
| 	if !keyelem.IsValid() { | ||||
| 		keyelem = reflect.Zero(p.mtype.Key()) | ||||
| 	} | ||||
| 	if !valelem.IsValid() { | ||||
| 		valelem = reflect.Zero(p.mtype.Elem()) | ||||
| 	} | ||||
| 
 | ||||
| 	v.SetMapIndex(keyelem, valelem) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Decode a group.
 | ||||
| func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { | ||||
| 	bas := structPointer_GetStructPointer(base, p.field) | ||||
| 	if structPointer_IsNil(bas) { | ||||
| 		// allocate new nested message
 | ||||
| 		bas = toStructPointer(reflect.New(p.stype)) | ||||
| 		structPointer_SetStructPointer(base, p.field, bas) | ||||
| 	} | ||||
| 	return o.unmarshalType(p.stype, p.sprop, true, bas) | ||||
| } | ||||
| 
 | ||||
| // Decode an embedded message.
 | ||||
| func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { | ||||
| 	raw, e := o.DecodeRawBytes(false) | ||||
| 	if e != nil { | ||||
| 		return e | ||||
| 	} | ||||
| 
 | ||||
| 	bas := structPointer_GetStructPointer(base, p.field) | ||||
| 	if structPointer_IsNil(bas) { | ||||
| 		// allocate new nested message
 | ||||
| 		bas = toStructPointer(reflect.New(p.stype)) | ||||
| 		structPointer_SetStructPointer(base, p.field, bas) | ||||
| 	} | ||||
| 
 | ||||
| 	// If the object can unmarshal itself, let it.
 | ||||
| 	if p.isUnmarshaler { | ||||
| 		iv := structPointer_Interface(bas, p.stype) | ||||
| 		return iv.(Unmarshaler).Unmarshal(raw) | ||||
| 	} | ||||
| 
 | ||||
| 	obuf := o.buf | ||||
| 	oi := o.index | ||||
| 	o.buf = raw | ||||
| 	o.index = 0 | ||||
| 
 | ||||
| 	err = o.unmarshalType(p.stype, p.sprop, false, bas) | ||||
| 	o.buf = obuf | ||||
| 	o.index = oi | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of embedded messages.
 | ||||
| func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { | ||||
| 	return o.dec_slice_struct(p, false, base) | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of embedded groups.
 | ||||
| func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { | ||||
| 	return o.dec_slice_struct(p, true, base) | ||||
| } | ||||
| 
 | ||||
| // Decode a slice of structs ([]*struct).
 | ||||
| func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { | ||||
| 	v := reflect.New(p.stype) | ||||
| 	bas := toStructPointer(v) | ||||
| 	structPointer_StructPointerSlice(base, p.field).Append(bas) | ||||
| 
 | ||||
| 	if is_group { | ||||
| 		err := o.unmarshalType(p.stype, p.sprop, is_group, bas) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	raw, err := o.DecodeRawBytes(false) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// If the object can unmarshal itself, let it.
 | ||||
| 	if p.isUnmarshaler { | ||||
| 		iv := v.Interface() | ||||
| 		return iv.(Unmarshaler).Unmarshal(raw) | ||||
| 	} | ||||
| 
 | ||||
| 	obuf := o.buf | ||||
| 	oi := o.index | ||||
| 	o.buf = raw | ||||
| 	o.index = 0 | ||||
| 
 | ||||
| 	err = o.unmarshalType(p.stype, p.sprop, is_group, bas) | ||||
| 
 | ||||
| 	o.buf = obuf | ||||
| 	o.index = oi | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,300 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2011 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| // Protocol buffer comparison.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"log" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| /* | ||||
| Equal returns true iff protocol buffers a and b are equal. | ||||
| The arguments must both be pointers to protocol buffer structs. | ||||
| 
 | ||||
| Equality is defined in this way: | ||||
|   - Two messages are equal iff they are the same type, | ||||
|     corresponding fields are equal, unknown field sets | ||||
|     are equal, and extensions sets are equal. | ||||
|   - Two set scalar fields are equal iff their values are equal. | ||||
|     If the fields are of a floating-point type, remember that | ||||
|     NaN != x for all x, including NaN. If the message is defined | ||||
|     in a proto3 .proto file, fields are not "set"; specifically, | ||||
|     zero length proto3 "bytes" fields are equal (nil == {}). | ||||
|   - Two repeated fields are equal iff their lengths are the same, | ||||
|     and their corresponding elements are equal. Note a "bytes" field, | ||||
|     although represented by []byte, is not a repeated field and the | ||||
|     rule for the scalar fields described above applies. | ||||
|   - Two unset fields are equal. | ||||
|   - Two unknown field sets are equal if their current | ||||
|     encoded state is equal. | ||||
|   - Two extension sets are equal iff they have corresponding | ||||
|     elements that are pairwise equal. | ||||
|   - Two map fields are equal iff their lengths are the same, | ||||
|     and they contain the same set of elements. Zero-length map | ||||
|     fields are equal. | ||||
|   - Every other combination of things are not equal. | ||||
| 
 | ||||
| The return value is undefined if a and b are not protocol buffers. | ||||
| */ | ||||
| func Equal(a, b Message) bool { | ||||
| 	if a == nil || b == nil { | ||||
| 		return a == b | ||||
| 	} | ||||
| 	v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) | ||||
| 	if v1.Type() != v2.Type() { | ||||
| 		return false | ||||
| 	} | ||||
| 	if v1.Kind() == reflect.Ptr { | ||||
| 		if v1.IsNil() { | ||||
| 			return v2.IsNil() | ||||
| 		} | ||||
| 		if v2.IsNil() { | ||||
| 			return false | ||||
| 		} | ||||
| 		v1, v2 = v1.Elem(), v2.Elem() | ||||
| 	} | ||||
| 	if v1.Kind() != reflect.Struct { | ||||
| 		return false | ||||
| 	} | ||||
| 	return equalStruct(v1, v2) | ||||
| } | ||||
| 
 | ||||
| // v1 and v2 are known to have the same type.
 | ||||
| func equalStruct(v1, v2 reflect.Value) bool { | ||||
| 	sprop := GetProperties(v1.Type()) | ||||
| 	for i := 0; i < v1.NumField(); i++ { | ||||
| 		f := v1.Type().Field(i) | ||||
| 		if strings.HasPrefix(f.Name, "XXX_") { | ||||
| 			continue | ||||
| 		} | ||||
| 		f1, f2 := v1.Field(i), v2.Field(i) | ||||
| 		if f.Type.Kind() == reflect.Ptr { | ||||
| 			if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { | ||||
| 				// both unset
 | ||||
| 				continue | ||||
| 			} else if n1 != n2 { | ||||
| 				// set/unset mismatch
 | ||||
| 				return false | ||||
| 			} | ||||
| 			b1, ok := f1.Interface().(raw) | ||||
| 			if ok { | ||||
| 				b2 := f2.Interface().(raw) | ||||
| 				// RawMessage
 | ||||
| 				if !bytes.Equal(b1.Bytes(), b2.Bytes()) { | ||||
| 					return false | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
| 			f1, f2 = f1.Elem(), f2.Elem() | ||||
| 		} | ||||
| 		if !equalAny(f1, f2, sprop.Prop[i]) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { | ||||
| 		em2 := v2.FieldByName("XXX_InternalExtensions") | ||||
| 		if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { | ||||
| 		em2 := v2.FieldByName("XXX_extensions") | ||||
| 		if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	uf := v1.FieldByName("XXX_unrecognized") | ||||
| 	if !uf.IsValid() { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	u1 := uf.Bytes() | ||||
| 	u2 := v2.FieldByName("XXX_unrecognized").Bytes() | ||||
| 	if !bytes.Equal(u1, u2) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // v1 and v2 are known to have the same type.
 | ||||
| // prop may be nil.
 | ||||
| func equalAny(v1, v2 reflect.Value, prop *Properties) bool { | ||||
| 	if v1.Type() == protoMessageType { | ||||
| 		m1, _ := v1.Interface().(Message) | ||||
| 		m2, _ := v2.Interface().(Message) | ||||
| 		return Equal(m1, m2) | ||||
| 	} | ||||
| 	switch v1.Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		return v1.Bool() == v2.Bool() | ||||
| 	case reflect.Float32, reflect.Float64: | ||||
| 		return v1.Float() == v2.Float() | ||||
| 	case reflect.Int32, reflect.Int64: | ||||
| 		return v1.Int() == v2.Int() | ||||
| 	case reflect.Interface: | ||||
| 		// Probably a oneof field; compare the inner values.
 | ||||
| 		n1, n2 := v1.IsNil(), v2.IsNil() | ||||
| 		if n1 || n2 { | ||||
| 			return n1 == n2 | ||||
| 		} | ||||
| 		e1, e2 := v1.Elem(), v2.Elem() | ||||
| 		if e1.Type() != e2.Type() { | ||||
| 			return false | ||||
| 		} | ||||
| 		return equalAny(e1, e2, nil) | ||||
| 	case reflect.Map: | ||||
| 		if v1.Len() != v2.Len() { | ||||
| 			return false | ||||
| 		} | ||||
| 		for _, key := range v1.MapKeys() { | ||||
| 			val2 := v2.MapIndex(key) | ||||
| 			if !val2.IsValid() { | ||||
| 				// This key was not found in the second map.
 | ||||
| 				return false | ||||
| 			} | ||||
| 			if !equalAny(v1.MapIndex(key), val2, nil) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 		return true | ||||
| 	case reflect.Ptr: | ||||
| 		// Maps may have nil values in them, so check for nil.
 | ||||
| 		if v1.IsNil() && v2.IsNil() { | ||||
| 			return true | ||||
| 		} | ||||
| 		if v1.IsNil() != v2.IsNil() { | ||||
| 			return false | ||||
| 		} | ||||
| 		return equalAny(v1.Elem(), v2.Elem(), prop) | ||||
| 	case reflect.Slice: | ||||
| 		if v1.Type().Elem().Kind() == reflect.Uint8 { | ||||
| 			// short circuit: []byte
 | ||||
| 
 | ||||
| 			// Edge case: if this is in a proto3 message, a zero length
 | ||||
| 			// bytes field is considered the zero value.
 | ||||
| 			if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { | ||||
| 				return true | ||||
| 			} | ||||
| 			if v1.IsNil() != v2.IsNil() { | ||||
| 				return false | ||||
| 			} | ||||
| 			return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) | ||||
| 		} | ||||
| 
 | ||||
| 		if v1.Len() != v2.Len() { | ||||
| 			return false | ||||
| 		} | ||||
| 		for i := 0; i < v1.Len(); i++ { | ||||
| 			if !equalAny(v1.Index(i), v2.Index(i), prop) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
| 		return true | ||||
| 	case reflect.String: | ||||
| 		return v1.Interface().(string) == v2.Interface().(string) | ||||
| 	case reflect.Struct: | ||||
| 		return equalStruct(v1, v2) | ||||
| 	case reflect.Uint32, reflect.Uint64: | ||||
| 		return v1.Uint() == v2.Uint() | ||||
| 	} | ||||
| 
 | ||||
| 	// unknown type, so not a protocol buffer
 | ||||
| 	log.Printf("proto: don't know how to compare %v", v1) | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // base is the struct type that the extensions are based on.
 | ||||
| // x1 and x2 are InternalExtensions.
 | ||||
| func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { | ||||
| 	em1, _ := x1.extensionsRead() | ||||
| 	em2, _ := x2.extensionsRead() | ||||
| 	return equalExtMap(base, em1, em2) | ||||
| } | ||||
| 
 | ||||
| func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { | ||||
| 	if len(em1) != len(em2) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	for extNum, e1 := range em1 { | ||||
| 		e2, ok := em2[extNum] | ||||
| 		if !ok { | ||||
| 			return false | ||||
| 		} | ||||
| 
 | ||||
| 		m1, m2 := e1.value, e2.value | ||||
| 
 | ||||
| 		if m1 != nil && m2 != nil { | ||||
| 			// Both are unencoded.
 | ||||
| 			if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { | ||||
| 				return false | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// At least one is encoded. To do a semantically correct comparison
 | ||||
| 		// we need to unmarshal them first.
 | ||||
| 		var desc *ExtensionDesc | ||||
| 		if m := extensionMaps[base]; m != nil { | ||||
| 			desc = m[extNum] | ||||
| 		} | ||||
| 		if desc == nil { | ||||
| 			log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) | ||||
| 			continue | ||||
| 		} | ||||
| 		var err error | ||||
| 		if m1 == nil { | ||||
| 			m1, err = decodeExtension(e1.enc, desc) | ||||
| 		} | ||||
| 		if m2 == nil && err == nil { | ||||
| 			m2, err = decodeExtension(e2.enc, desc) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			// The encoded form is invalid.
 | ||||
| 			log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) | ||||
| 			return false | ||||
| 		} | ||||
| 		if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
|  | @ -0,0 +1,586 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| /* | ||||
|  * Types and routines for supporting protocol buffer extensions. | ||||
|  */ | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| // ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.
 | ||||
| var ErrMissingExtension = errors.New("proto: missing extension") | ||||
| 
 | ||||
| // ExtensionRange represents a range of message extensions for a protocol buffer.
 | ||||
| // Used in code generated by the protocol compiler.
 | ||||
| type ExtensionRange struct { | ||||
| 	Start, End int32 // both inclusive
 | ||||
| } | ||||
| 
 | ||||
| // extendableProto is an interface implemented by any protocol buffer generated by the current
 | ||||
| // proto compiler that may be extended.
 | ||||
| type extendableProto interface { | ||||
| 	Message | ||||
| 	ExtensionRangeArray() []ExtensionRange | ||||
| 	extensionsWrite() map[int32]Extension | ||||
| 	extensionsRead() (map[int32]Extension, sync.Locker) | ||||
| } | ||||
| 
 | ||||
| // extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous
 | ||||
| // version of the proto compiler that may be extended.
 | ||||
| type extendableProtoV1 interface { | ||||
| 	Message | ||||
| 	ExtensionRangeArray() []ExtensionRange | ||||
| 	ExtensionMap() map[int32]Extension | ||||
| } | ||||
| 
 | ||||
| // extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto.
 | ||||
| type extensionAdapter struct { | ||||
| 	extendableProtoV1 | ||||
| } | ||||
| 
 | ||||
| func (e extensionAdapter) extensionsWrite() map[int32]Extension { | ||||
| 	return e.ExtensionMap() | ||||
| } | ||||
| 
 | ||||
| func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { | ||||
| 	return e.ExtensionMap(), notLocker{} | ||||
| } | ||||
| 
 | ||||
| // notLocker is a sync.Locker whose Lock and Unlock methods are nops.
 | ||||
| type notLocker struct{} | ||||
| 
 | ||||
| func (n notLocker) Lock()   {} | ||||
| func (n notLocker) Unlock() {} | ||||
| 
 | ||||
| // extendable returns the extendableProto interface for the given generated proto message.
 | ||||
| // If the proto message has the old extension format, it returns a wrapper that implements
 | ||||
| // the extendableProto interface.
 | ||||
| func extendable(p interface{}) (extendableProto, bool) { | ||||
| 	if ep, ok := p.(extendableProto); ok { | ||||
| 		return ep, ok | ||||
| 	} | ||||
| 	if ep, ok := p.(extendableProtoV1); ok { | ||||
| 		return extensionAdapter{ep}, ok | ||||
| 	} | ||||
| 	return nil, false | ||||
| } | ||||
| 
 | ||||
| // XXX_InternalExtensions is an internal representation of proto extensions.
 | ||||
| //
 | ||||
| // Each generated message struct type embeds an anonymous XXX_InternalExtensions field,
 | ||||
| // thus gaining the unexported 'extensions' method, which can be called only from the proto package.
 | ||||
| //
 | ||||
| // The methods of XXX_InternalExtensions are not concurrency safe in general,
 | ||||
| // but calls to logically read-only methods such as has and get may be executed concurrently.
 | ||||
| type XXX_InternalExtensions struct { | ||||
| 	// The struct must be indirect so that if a user inadvertently copies a
 | ||||
| 	// generated message and its embedded XXX_InternalExtensions, they
 | ||||
| 	// avoid the mayhem of a copied mutex.
 | ||||
| 	//
 | ||||
| 	// The mutex serializes all logically read-only operations to p.extensionMap.
 | ||||
| 	// It is up to the client to ensure that write operations to p.extensionMap are
 | ||||
| 	// mutually exclusive with other accesses.
 | ||||
| 	p *struct { | ||||
| 		mu           sync.Mutex | ||||
| 		extensionMap map[int32]Extension | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // extensionsWrite returns the extension map, creating it on first use.
 | ||||
| func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { | ||||
| 	if e.p == nil { | ||||
| 		e.p = new(struct { | ||||
| 			mu           sync.Mutex | ||||
| 			extensionMap map[int32]Extension | ||||
| 		}) | ||||
| 		e.p.extensionMap = make(map[int32]Extension) | ||||
| 	} | ||||
| 	return e.p.extensionMap | ||||
| } | ||||
| 
 | ||||
| // extensionsRead returns the extensions map for read-only use.  It may be nil.
 | ||||
| // The caller must hold the returned mutex's lock when accessing Elements within the map.
 | ||||
| func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { | ||||
| 	if e.p == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	return e.p.extensionMap, &e.p.mu | ||||
| } | ||||
| 
 | ||||
| var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() | ||||
| var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() | ||||
| 
 | ||||
| // ExtensionDesc represents an extension specification.
 | ||||
| // Used in generated code from the protocol compiler.
 | ||||
| type ExtensionDesc struct { | ||||
| 	ExtendedType  Message     // nil pointer to the type that is being extended
 | ||||
| 	ExtensionType interface{} // nil pointer to the extension type
 | ||||
| 	Field         int32       // field number
 | ||||
| 	Name          string      // fully-qualified name of extension, for text formatting
 | ||||
| 	Tag           string      // protobuf tag style
 | ||||
| } | ||||
| 
 | ||||
| func (ed *ExtensionDesc) repeated() bool { | ||||
| 	t := reflect.TypeOf(ed.ExtensionType) | ||||
| 	return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 | ||||
| } | ||||
| 
 | ||||
| // Extension represents an extension in a message.
 | ||||
| type Extension struct { | ||||
| 	// When an extension is stored in a message using SetExtension
 | ||||
| 	// only desc and value are set. When the message is marshaled
 | ||||
| 	// enc will be set to the encoded form of the message.
 | ||||
| 	//
 | ||||
| 	// When a message is unmarshaled and contains extensions, each
 | ||||
| 	// extension will have only enc set. When such an extension is
 | ||||
| 	// accessed using GetExtension (or GetExtensions) desc and value
 | ||||
| 	// will be set.
 | ||||
| 	desc  *ExtensionDesc | ||||
| 	value interface{} | ||||
| 	enc   []byte | ||||
| } | ||||
| 
 | ||||
| // SetRawExtension is for testing only.
 | ||||
| func SetRawExtension(base Message, id int32, b []byte) { | ||||
| 	epb, ok := extendable(base) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	extmap := epb.extensionsWrite() | ||||
| 	extmap[id] = Extension{enc: b} | ||||
| } | ||||
| 
 | ||||
| // isExtensionField returns true iff the given field number is in an extension range.
 | ||||
| func isExtensionField(pb extendableProto, field int32) bool { | ||||
| 	for _, er := range pb.ExtensionRangeArray() { | ||||
| 		if er.Start <= field && field <= er.End { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // checkExtensionTypes checks that the given extension is valid for pb.
 | ||||
| func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { | ||||
| 	var pbi interface{} = pb | ||||
| 	// Check the extended type.
 | ||||
| 	if ea, ok := pbi.(extensionAdapter); ok { | ||||
| 		pbi = ea.extendableProtoV1 | ||||
| 	} | ||||
| 	if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { | ||||
| 		return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) | ||||
| 	} | ||||
| 	// Check the range.
 | ||||
| 	if !isExtensionField(pb, extension.Field) { | ||||
| 		return errors.New("proto: bad extension number; not in declared ranges") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // extPropKey is sufficient to uniquely identify an extension.
 | ||||
| type extPropKey struct { | ||||
| 	base  reflect.Type | ||||
| 	field int32 | ||||
| } | ||||
| 
 | ||||
| var extProp = struct { | ||||
| 	sync.RWMutex | ||||
| 	m map[extPropKey]*Properties | ||||
| }{ | ||||
| 	m: make(map[extPropKey]*Properties), | ||||
| } | ||||
| 
 | ||||
| func extensionProperties(ed *ExtensionDesc) *Properties { | ||||
| 	key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} | ||||
| 
 | ||||
| 	extProp.RLock() | ||||
| 	if prop, ok := extProp.m[key]; ok { | ||||
| 		extProp.RUnlock() | ||||
| 		return prop | ||||
| 	} | ||||
| 	extProp.RUnlock() | ||||
| 
 | ||||
| 	extProp.Lock() | ||||
| 	defer extProp.Unlock() | ||||
| 	// Check again.
 | ||||
| 	if prop, ok := extProp.m[key]; ok { | ||||
| 		return prop | ||||
| 	} | ||||
| 
 | ||||
| 	prop := new(Properties) | ||||
| 	prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) | ||||
| 	extProp.m[key] = prop | ||||
| 	return prop | ||||
| } | ||||
| 
 | ||||
| // encode encodes any unmarshaled (unencoded) extensions in e.
 | ||||
| func encodeExtensions(e *XXX_InternalExtensions) error { | ||||
| 	m, mu := e.extensionsRead() | ||||
| 	if m == nil { | ||||
| 		return nil // fast path
 | ||||
| 	} | ||||
| 	mu.Lock() | ||||
| 	defer mu.Unlock() | ||||
| 	return encodeExtensionsMap(m) | ||||
| } | ||||
| 
 | ||||
| // encode encodes any unmarshaled (unencoded) extensions in e.
 | ||||
| func encodeExtensionsMap(m map[int32]Extension) error { | ||||
| 	for k, e := range m { | ||||
| 		if e.value == nil || e.desc == nil { | ||||
| 			// Extension is only in its encoded form.
 | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// We don't skip extensions that have an encoded form set,
 | ||||
| 		// because the extension value may have been mutated after
 | ||||
| 		// the last time this function was called.
 | ||||
| 
 | ||||
| 		et := reflect.TypeOf(e.desc.ExtensionType) | ||||
| 		props := extensionProperties(e.desc) | ||||
| 
 | ||||
| 		p := NewBuffer(nil) | ||||
| 		// If e.value has type T, the encoder expects a *struct{ X T }.
 | ||||
| 		// Pass a *T with a zero field and hope it all works out.
 | ||||
| 		x := reflect.New(et) | ||||
| 		x.Elem().Set(reflect.ValueOf(e.value)) | ||||
| 		if err := props.enc(p, props, toStructPointer(x)); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		e.enc = p.buf | ||||
| 		m[k] = e | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func extensionsSize(e *XXX_InternalExtensions) (n int) { | ||||
| 	m, mu := e.extensionsRead() | ||||
| 	if m == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	mu.Lock() | ||||
| 	defer mu.Unlock() | ||||
| 	return extensionsMapSize(m) | ||||
| } | ||||
| 
 | ||||
| func extensionsMapSize(m map[int32]Extension) (n int) { | ||||
| 	for _, e := range m { | ||||
| 		if e.value == nil || e.desc == nil { | ||||
| 			// Extension is only in its encoded form.
 | ||||
| 			n += len(e.enc) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// We don't skip extensions that have an encoded form set,
 | ||||
| 		// because the extension value may have been mutated after
 | ||||
| 		// the last time this function was called.
 | ||||
| 
 | ||||
| 		et := reflect.TypeOf(e.desc.ExtensionType) | ||||
| 		props := extensionProperties(e.desc) | ||||
| 
 | ||||
| 		// If e.value has type T, the encoder expects a *struct{ X T }.
 | ||||
| 		// Pass a *T with a zero field and hope it all works out.
 | ||||
| 		x := reflect.New(et) | ||||
| 		x.Elem().Set(reflect.ValueOf(e.value)) | ||||
| 		n += props.size(props, toStructPointer(x)) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // HasExtension returns whether the given extension is present in pb.
 | ||||
| func HasExtension(pb Message, extension *ExtensionDesc) bool { | ||||
| 	// TODO: Check types, field numbers, etc.?
 | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	extmap, mu := epb.extensionsRead() | ||||
| 	if extmap == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	mu.Lock() | ||||
| 	_, ok = extmap[extension.Field] | ||||
| 	mu.Unlock() | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| // ClearExtension removes the given extension from pb.
 | ||||
| func ClearExtension(pb Message, extension *ExtensionDesc) { | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	// TODO: Check types, field numbers, etc.?
 | ||||
| 	extmap := epb.extensionsWrite() | ||||
| 	delete(extmap, extension.Field) | ||||
| } | ||||
| 
 | ||||
| // GetExtension parses and returns the given extension of pb.
 | ||||
| // If the extension is not present and has no default value it returns ErrMissingExtension.
 | ||||
| func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("proto: not an extendable proto") | ||||
| 	} | ||||
| 
 | ||||
| 	if err := checkExtensionTypes(epb, extension); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	emap, mu := epb.extensionsRead() | ||||
| 	if emap == nil { | ||||
| 		return defaultExtensionValue(extension) | ||||
| 	} | ||||
| 	mu.Lock() | ||||
| 	defer mu.Unlock() | ||||
| 	e, ok := emap[extension.Field] | ||||
| 	if !ok { | ||||
| 		// defaultExtensionValue returns the default value or
 | ||||
| 		// ErrMissingExtension if there is no default.
 | ||||
| 		return defaultExtensionValue(extension) | ||||
| 	} | ||||
| 
 | ||||
| 	if e.value != nil { | ||||
| 		// Already decoded. Check the descriptor, though.
 | ||||
| 		if e.desc != extension { | ||||
| 			// This shouldn't happen. If it does, it means that
 | ||||
| 			// GetExtension was called twice with two different
 | ||||
| 			// descriptors with the same field number.
 | ||||
| 			return nil, errors.New("proto: descriptor conflict") | ||||
| 		} | ||||
| 		return e.value, nil | ||||
| 	} | ||||
| 
 | ||||
| 	v, err := decodeExtension(e.enc, extension) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Remember the decoded version and drop the encoded version.
 | ||||
| 	// That way it is safe to mutate what we return.
 | ||||
| 	e.value = v | ||||
| 	e.desc = extension | ||||
| 	e.enc = nil | ||||
| 	emap[extension.Field] = e | ||||
| 	return e.value, nil | ||||
| } | ||||
| 
 | ||||
| // defaultExtensionValue returns the default value for extension.
 | ||||
| // If no default for an extension is defined ErrMissingExtension is returned.
 | ||||
| func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { | ||||
| 	t := reflect.TypeOf(extension.ExtensionType) | ||||
| 	props := extensionProperties(extension) | ||||
| 
 | ||||
| 	sf, _, err := fieldDefault(t, props) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if sf == nil || sf.value == nil { | ||||
| 		// There is no default value.
 | ||||
| 		return nil, ErrMissingExtension | ||||
| 	} | ||||
| 
 | ||||
| 	if t.Kind() != reflect.Ptr { | ||||
| 		// We do not need to return a Ptr, we can directly return sf.value.
 | ||||
| 		return sf.value, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// We need to return an interface{} that is a pointer to sf.value.
 | ||||
| 	value := reflect.New(t).Elem() | ||||
| 	value.Set(reflect.New(value.Type().Elem())) | ||||
| 	if sf.kind == reflect.Int32 { | ||||
| 		// We may have an int32 or an enum, but the underlying data is int32.
 | ||||
| 		// Since we can't set an int32 into a non int32 reflect.value directly
 | ||||
| 		// set it as a int32.
 | ||||
| 		value.Elem().SetInt(int64(sf.value.(int32))) | ||||
| 	} else { | ||||
| 		value.Elem().Set(reflect.ValueOf(sf.value)) | ||||
| 	} | ||||
| 	return value.Interface(), nil | ||||
| } | ||||
| 
 | ||||
| // decodeExtension decodes an extension encoded in b.
 | ||||
| func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { | ||||
| 	o := NewBuffer(b) | ||||
| 
 | ||||
| 	t := reflect.TypeOf(extension.ExtensionType) | ||||
| 
 | ||||
| 	props := extensionProperties(extension) | ||||
| 
 | ||||
| 	// t is a pointer to a struct, pointer to basic type or a slice.
 | ||||
| 	// Allocate a "field" to store the pointer/slice itself; the
 | ||||
| 	// pointer/slice will be stored here. We pass
 | ||||
| 	// the address of this field to props.dec.
 | ||||
| 	// This passes a zero field and a *t and lets props.dec
 | ||||
| 	// interpret it as a *struct{ x t }.
 | ||||
| 	value := reflect.New(t).Elem() | ||||
| 
 | ||||
| 	for { | ||||
| 		// Discard wire type and field number varint. It isn't needed.
 | ||||
| 		if _, err := o.DecodeVarint(); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		if o.index >= len(o.buf) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return value.Interface(), nil | ||||
| } | ||||
| 
 | ||||
| // GetExtensions returns a slice of the extensions present in pb that are also listed in es.
 | ||||
| // The returned slice has the same length as es; missing extensions will appear as nil elements.
 | ||||
| func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("proto: not an extendable proto") | ||||
| 	} | ||||
| 	extensions = make([]interface{}, len(es)) | ||||
| 	for i, e := range es { | ||||
| 		extensions[i], err = GetExtension(epb, e) | ||||
| 		if err == ErrMissingExtension { | ||||
| 			err = nil | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order.
 | ||||
| // For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
 | ||||
| // just the Field field, which defines the extension's field number.
 | ||||
| func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) | ||||
| 	} | ||||
| 	registeredExtensions := RegisteredExtensions(pb) | ||||
| 
 | ||||
| 	emap, mu := epb.extensionsRead() | ||||
| 	if emap == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	mu.Lock() | ||||
| 	defer mu.Unlock() | ||||
| 	extensions := make([]*ExtensionDesc, 0, len(emap)) | ||||
| 	for extid, e := range emap { | ||||
| 		desc := e.desc | ||||
| 		if desc == nil { | ||||
| 			desc = registeredExtensions[extid] | ||||
| 			if desc == nil { | ||||
| 				desc = &ExtensionDesc{Field: extid} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		extensions = append(extensions, desc) | ||||
| 	} | ||||
| 	return extensions, nil | ||||
| } | ||||
| 
 | ||||
| // SetExtension sets the specified extension of pb to the specified value.
 | ||||
| func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return errors.New("proto: not an extendable proto") | ||||
| 	} | ||||
| 	if err := checkExtensionTypes(epb, extension); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	typ := reflect.TypeOf(extension.ExtensionType) | ||||
| 	if typ != reflect.TypeOf(value) { | ||||
| 		return errors.New("proto: bad extension value type") | ||||
| 	} | ||||
| 	// nil extension values need to be caught early, because the
 | ||||
| 	// encoder can't distinguish an ErrNil due to a nil extension
 | ||||
| 	// from an ErrNil due to a missing field. Extensions are
 | ||||
| 	// always optional, so the encoder would just swallow the error
 | ||||
| 	// and drop all the extensions from the encoded message.
 | ||||
| 	if reflect.ValueOf(value).IsNil() { | ||||
| 		return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) | ||||
| 	} | ||||
| 
 | ||||
| 	extmap := epb.extensionsWrite() | ||||
| 	extmap[extension.Field] = Extension{desc: extension, value: value} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ClearAllExtensions clears all extensions from pb.
 | ||||
| func ClearAllExtensions(pb Message) { | ||||
| 	epb, ok := extendable(pb) | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	m := epb.extensionsWrite() | ||||
| 	for k := range m { | ||||
| 		delete(m, k) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // A global registry of extensions.
 | ||||
| // The generated code will register the generated descriptors by calling RegisterExtension.
 | ||||
| 
 | ||||
| var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) | ||||
| 
 | ||||
| // RegisterExtension is called from the generated code.
 | ||||
| func RegisterExtension(desc *ExtensionDesc) { | ||||
| 	st := reflect.TypeOf(desc.ExtendedType).Elem() | ||||
| 	m := extensionMaps[st] | ||||
| 	if m == nil { | ||||
| 		m = make(map[int32]*ExtensionDesc) | ||||
| 		extensionMaps[st] = m | ||||
| 	} | ||||
| 	if _, ok := m[desc.Field]; ok { | ||||
| 		panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) | ||||
| 	} | ||||
| 	m[desc.Field] = desc | ||||
| } | ||||
| 
 | ||||
| // RegisteredExtensions returns a map of the registered extensions of a
 | ||||
| // protocol buffer struct, indexed by the extension number.
 | ||||
| // The argument pb should be a nil pointer to the struct type.
 | ||||
| func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { | ||||
| 	return extensionMaps[reflect.TypeOf(pb).Elem()] | ||||
| } | ||||
|  | @ -0,0 +1,898 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| /* | ||||
| Package proto converts data structures to and from the wire format of | ||||
| protocol buffers.  It works in concert with the Go source code generated | ||||
| for .proto files by the protocol compiler. | ||||
| 
 | ||||
| A summary of the properties of the protocol buffer interface | ||||
| for a protocol buffer variable v: | ||||
| 
 | ||||
|   - Names are turned from camel_case to CamelCase for export. | ||||
|   - There are no methods on v to set fields; just treat | ||||
| 	them as structure fields. | ||||
|   - There are getters that return a field's value if set, | ||||
| 	and return the field's default value if unset. | ||||
| 	The getters work even if the receiver is a nil message. | ||||
|   - The zero value for a struct is its correct initialization state. | ||||
| 	All desired fields must be set before marshaling. | ||||
|   - A Reset() method will restore a protobuf struct to its zero state. | ||||
|   - Non-repeated fields are pointers to the values; nil means unset. | ||||
| 	That is, optional or required field int32 f becomes F *int32. | ||||
|   - Repeated fields are slices. | ||||
|   - Helper functions are available to aid the setting of fields. | ||||
| 	msg.Foo = proto.String("hello") // set field
 | ||||
|   - Constants are defined to hold the default values of all fields that | ||||
| 	have them.  They have the form Default_StructName_FieldName. | ||||
| 	Because the getter methods handle defaulted values, | ||||
| 	direct use of these constants should be rare. | ||||
|   - Enums are given type names and maps from names to values. | ||||
| 	Enum values are prefixed by the enclosing message's name, or by the | ||||
| 	enum's type name if it is a top-level enum. Enum types have a String | ||||
| 	method, and a Enum method to assist in message construction. | ||||
|   - Nested messages, groups and enums have type names prefixed with the name of | ||||
| 	the surrounding message type. | ||||
|   - Extensions are given descriptor names that start with E_, | ||||
| 	followed by an underscore-delimited list of the nested messages | ||||
| 	that contain it (if any) followed by the CamelCased name of the | ||||
| 	extension field itself.  HasExtension, ClearExtension, GetExtension | ||||
| 	and SetExtension are functions for manipulating extensions. | ||||
|   - Oneof field sets are given a single field in their message, | ||||
| 	with distinguished wrapper types for each possible field value. | ||||
|   - Marshal and Unmarshal are functions to encode and decode the wire format. | ||||
| 
 | ||||
| When the .proto file specifies `syntax="proto3"`, there are some differences: | ||||
| 
 | ||||
|   - Non-repeated fields of non-message type are values instead of pointers. | ||||
|   - Getters are only generated for message and oneof fields. | ||||
|   - Enum types do not get an Enum method. | ||||
| 
 | ||||
| The simplest way to describe this is to see an example. | ||||
| Given file test.proto, containing | ||||
| 
 | ||||
| 	package example; | ||||
| 
 | ||||
| 	enum FOO { X = 17; } | ||||
| 
 | ||||
| 	message Test { | ||||
| 	  required string label = 1; | ||||
| 	  optional int32 type = 2 [default=77]; | ||||
| 	  repeated int64 reps = 3; | ||||
| 	  optional group OptionalGroup = 4 { | ||||
| 	    required string RequiredField = 5; | ||||
| 	  } | ||||
| 	  oneof union { | ||||
| 	    int32 number = 6; | ||||
| 	    string name = 7; | ||||
| 	  } | ||||
| 	} | ||||
| 
 | ||||
| The resulting file, test.pb.go, is: | ||||
| 
 | ||||
| 	package example | ||||
| 
 | ||||
| 	import proto "github.com/golang/protobuf/proto" | ||||
| 	import math "math" | ||||
| 
 | ||||
| 	type FOO int32 | ||||
| 	const ( | ||||
| 		FOO_X FOO = 17 | ||||
| 	) | ||||
| 	var FOO_name = map[int32]string{ | ||||
| 		17: "X", | ||||
| 	} | ||||
| 	var FOO_value = map[string]int32{ | ||||
| 		"X": 17, | ||||
| 	} | ||||
| 
 | ||||
| 	func (x FOO) Enum() *FOO { | ||||
| 		p := new(FOO) | ||||
| 		*p = x | ||||
| 		return p | ||||
| 	} | ||||
| 	func (x FOO) String() string { | ||||
| 		return proto.EnumName(FOO_name, int32(x)) | ||||
| 	} | ||||
| 	func (x *FOO) UnmarshalJSON(data []byte) error { | ||||
| 		value, err := proto.UnmarshalJSONEnum(FOO_value, data) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		*x = FOO(value) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	type Test struct { | ||||
| 		Label         *string             `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` | ||||
| 		Type          *int32              `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` | ||||
| 		Reps          []int64             `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` | ||||
| 		Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` | ||||
| 		// Types that are valid to be assigned to Union:
 | ||||
| 		//	*Test_Number
 | ||||
| 		//	*Test_Name
 | ||||
| 		Union            isTest_Union `protobuf_oneof:"union"` | ||||
| 		XXX_unrecognized []byte       `json:"-"` | ||||
| 	} | ||||
| 	func (m *Test) Reset()         { *m = Test{} } | ||||
| 	func (m *Test) String() string { return proto.CompactTextString(m) } | ||||
| 	func (*Test) ProtoMessage() {} | ||||
| 
 | ||||
| 	type isTest_Union interface { | ||||
| 		isTest_Union() | ||||
| 	} | ||||
| 
 | ||||
| 	type Test_Number struct { | ||||
| 		Number int32 `protobuf:"varint,6,opt,name=number"` | ||||
| 	} | ||||
| 	type Test_Name struct { | ||||
| 		Name string `protobuf:"bytes,7,opt,name=name"` | ||||
| 	} | ||||
| 
 | ||||
| 	func (*Test_Number) isTest_Union() {} | ||||
| 	func (*Test_Name) isTest_Union()   {} | ||||
| 
 | ||||
| 	func (m *Test) GetUnion() isTest_Union { | ||||
| 		if m != nil { | ||||
| 			return m.Union | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	const Default_Test_Type int32 = 77 | ||||
| 
 | ||||
| 	func (m *Test) GetLabel() string { | ||||
| 		if m != nil && m.Label != nil { | ||||
| 			return *m.Label | ||||
| 		} | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	func (m *Test) GetType() int32 { | ||||
| 		if m != nil && m.Type != nil { | ||||
| 			return *m.Type | ||||
| 		} | ||||
| 		return Default_Test_Type | ||||
| 	} | ||||
| 
 | ||||
| 	func (m *Test) GetOptionalgroup() *Test_OptionalGroup { | ||||
| 		if m != nil { | ||||
| 			return m.Optionalgroup | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	type Test_OptionalGroup struct { | ||||
| 		RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` | ||||
| 	} | ||||
| 	func (m *Test_OptionalGroup) Reset()         { *m = Test_OptionalGroup{} } | ||||
| 	func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } | ||||
| 
 | ||||
| 	func (m *Test_OptionalGroup) GetRequiredField() string { | ||||
| 		if m != nil && m.RequiredField != nil { | ||||
| 			return *m.RequiredField | ||||
| 		} | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	func (m *Test) GetNumber() int32 { | ||||
| 		if x, ok := m.GetUnion().(*Test_Number); ok { | ||||
| 			return x.Number | ||||
| 		} | ||||
| 		return 0 | ||||
| 	} | ||||
| 
 | ||||
| 	func (m *Test) GetName() string { | ||||
| 		if x, ok := m.GetUnion().(*Test_Name); ok { | ||||
| 			return x.Name | ||||
| 		} | ||||
| 		return "" | ||||
| 	} | ||||
| 
 | ||||
| 	func init() { | ||||
| 		proto.RegisterEnum("example.FOO", FOO_name, FOO_value) | ||||
| 	} | ||||
| 
 | ||||
| To create and play with a Test object: | ||||
| 
 | ||||
| 	package main | ||||
| 
 | ||||
| 	import ( | ||||
| 		"log" | ||||
| 
 | ||||
| 		"github.com/golang/protobuf/proto" | ||||
| 		pb "./example.pb" | ||||
| 	) | ||||
| 
 | ||||
| 	func main() { | ||||
| 		test := &pb.Test{ | ||||
| 			Label: proto.String("hello"), | ||||
| 			Type:  proto.Int32(17), | ||||
| 			Reps:  []int64{1, 2, 3}, | ||||
| 			Optionalgroup: &pb.Test_OptionalGroup{ | ||||
| 				RequiredField: proto.String("good bye"), | ||||
| 			}, | ||||
| 			Union: &pb.Test_Name{"fred"}, | ||||
| 		} | ||||
| 		data, err := proto.Marshal(test) | ||||
| 		if err != nil { | ||||
| 			log.Fatal("marshaling error: ", err) | ||||
| 		} | ||||
| 		newTest := &pb.Test{} | ||||
| 		err = proto.Unmarshal(data, newTest) | ||||
| 		if err != nil { | ||||
| 			log.Fatal("unmarshaling error: ", err) | ||||
| 		} | ||||
| 		// Now test and newTest contain the same data.
 | ||||
| 		if test.GetLabel() != newTest.GetLabel() { | ||||
| 			log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) | ||||
| 		} | ||||
| 		// Use a type switch to determine which oneof was set.
 | ||||
| 		switch u := test.Union.(type) { | ||||
| 		case *pb.Test_Number: // u.Number contains the number.
 | ||||
| 		case *pb.Test_Name: // u.Name contains the string.
 | ||||
| 		} | ||||
| 		// etc.
 | ||||
| 	} | ||||
| */ | ||||
| package proto | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| // Message is implemented by generated protocol buffer messages.
 | ||||
| type Message interface { | ||||
| 	Reset() | ||||
| 	String() string | ||||
| 	ProtoMessage() | ||||
| } | ||||
| 
 | ||||
| // Stats records allocation details about the protocol buffer encoders
 | ||||
| // and decoders.  Useful for tuning the library itself.
 | ||||
| type Stats struct { | ||||
| 	Emalloc uint64 // mallocs in encode
 | ||||
| 	Dmalloc uint64 // mallocs in decode
 | ||||
| 	Encode  uint64 // number of encodes
 | ||||
| 	Decode  uint64 // number of decodes
 | ||||
| 	Chit    uint64 // number of cache hits
 | ||||
| 	Cmiss   uint64 // number of cache misses
 | ||||
| 	Size    uint64 // number of sizes
 | ||||
| } | ||||
| 
 | ||||
| // Set to true to enable stats collection.
 | ||||
| const collectStats = false | ||||
| 
 | ||||
| var stats Stats | ||||
| 
 | ||||
| // GetStats returns a copy of the global Stats structure.
 | ||||
| func GetStats() Stats { return stats } | ||||
| 
 | ||||
| // A Buffer is a buffer manager for marshaling and unmarshaling
 | ||||
| // protocol buffers.  It may be reused between invocations to
 | ||||
| // reduce memory usage.  It is not necessary to use a Buffer;
 | ||||
| // the global functions Marshal and Unmarshal create a
 | ||||
| // temporary Buffer and are fine for most applications.
 | ||||
| type Buffer struct { | ||||
| 	buf   []byte // encode/decode byte stream
 | ||||
| 	index int    // read point
 | ||||
| 
 | ||||
| 	// pools of basic types to amortize allocation.
 | ||||
| 	bools   []bool | ||||
| 	uint32s []uint32 | ||||
| 	uint64s []uint64 | ||||
| 
 | ||||
| 	// extra pools, only used with pointer_reflect.go
 | ||||
| 	int32s   []int32 | ||||
| 	int64s   []int64 | ||||
| 	float32s []float32 | ||||
| 	float64s []float64 | ||||
| } | ||||
| 
 | ||||
| // NewBuffer allocates a new Buffer and initializes its internal data to
 | ||||
| // the contents of the argument slice.
 | ||||
| func NewBuffer(e []byte) *Buffer { | ||||
| 	return &Buffer{buf: e} | ||||
| } | ||||
| 
 | ||||
| // Reset resets the Buffer, ready for marshaling a new protocol buffer.
 | ||||
| func (p *Buffer) Reset() { | ||||
| 	p.buf = p.buf[0:0] // for reading/writing
 | ||||
| 	p.index = 0        // for reading
 | ||||
| } | ||||
| 
 | ||||
| // SetBuf replaces the internal buffer with the slice,
 | ||||
| // ready for unmarshaling the contents of the slice.
 | ||||
| func (p *Buffer) SetBuf(s []byte) { | ||||
| 	p.buf = s | ||||
| 	p.index = 0 | ||||
| } | ||||
| 
 | ||||
| // Bytes returns the contents of the Buffer.
 | ||||
| func (p *Buffer) Bytes() []byte { return p.buf } | ||||
| 
 | ||||
| /* | ||||
|  * Helper routines for simplifying the creation of optional fields of basic type. | ||||
|  */ | ||||
| 
 | ||||
| // Bool is a helper routine that allocates a new bool value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Bool(v bool) *bool { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // Int32 is a helper routine that allocates a new int32 value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Int32(v int32) *int32 { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // Int is a helper routine that allocates a new int32 value
 | ||||
| // to store v and returns a pointer to it, but unlike Int32
 | ||||
| // its argument value is an int.
 | ||||
| func Int(v int) *int32 { | ||||
| 	p := new(int32) | ||||
| 	*p = int32(v) | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| // Int64 is a helper routine that allocates a new int64 value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Int64(v int64) *int64 { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // Float32 is a helper routine that allocates a new float32 value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Float32(v float32) *float32 { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // Float64 is a helper routine that allocates a new float64 value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Float64(v float64) *float64 { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // Uint32 is a helper routine that allocates a new uint32 value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Uint32(v uint32) *uint32 { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // Uint64 is a helper routine that allocates a new uint64 value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func Uint64(v uint64) *uint64 { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // String is a helper routine that allocates a new string value
 | ||||
| // to store v and returns a pointer to it.
 | ||||
| func String(v string) *string { | ||||
| 	return &v | ||||
| } | ||||
| 
 | ||||
| // EnumName is a helper function to simplify printing protocol buffer enums
 | ||||
| // by name.  Given an enum map and a value, it returns a useful string.
 | ||||
| func EnumName(m map[int32]string, v int32) string { | ||||
| 	s, ok := m[v] | ||||
| 	if ok { | ||||
| 		return s | ||||
| 	} | ||||
| 	return strconv.Itoa(int(v)) | ||||
| } | ||||
| 
 | ||||
| // UnmarshalJSONEnum is a helper function to simplify recovering enum int values
 | ||||
| // from their JSON-encoded representation. Given a map from the enum's symbolic
 | ||||
| // names to its int values, and a byte buffer containing the JSON-encoded
 | ||||
| // value, it returns an int32 that can be cast to the enum type by the caller.
 | ||||
| //
 | ||||
| // The function can deal with both JSON representations, numeric and symbolic.
 | ||||
| func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { | ||||
| 	if data[0] == '"' { | ||||
| 		// New style: enums are strings.
 | ||||
| 		var repr string | ||||
| 		if err := json.Unmarshal(data, &repr); err != nil { | ||||
| 			return -1, err | ||||
| 		} | ||||
| 		val, ok := m[repr] | ||||
| 		if !ok { | ||||
| 			return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) | ||||
| 		} | ||||
| 		return val, nil | ||||
| 	} | ||||
| 	// Old style: enums are ints.
 | ||||
| 	var val int32 | ||||
| 	if err := json.Unmarshal(data, &val); err != nil { | ||||
| 		return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) | ||||
| 	} | ||||
| 	return val, nil | ||||
| } | ||||
| 
 | ||||
| // DebugPrint dumps the encoded data in b in a debugging format with a header
 | ||||
| // including the string s. Used in testing but made available for general debugging.
 | ||||
| func (p *Buffer) DebugPrint(s string, b []byte) { | ||||
| 	var u uint64 | ||||
| 
 | ||||
| 	obuf := p.buf | ||||
| 	index := p.index | ||||
| 	p.buf = b | ||||
| 	p.index = 0 | ||||
| 	depth := 0 | ||||
| 
 | ||||
| 	fmt.Printf("\n--- %s ---\n", s) | ||||
| 
 | ||||
| out: | ||||
| 	for { | ||||
| 		for i := 0; i < depth; i++ { | ||||
| 			fmt.Print("  ") | ||||
| 		} | ||||
| 
 | ||||
| 		index := p.index | ||||
| 		if index == len(p.buf) { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		op, err := p.DecodeVarint() | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("%3d: fetching op err %v\n", index, err) | ||||
| 			break out | ||||
| 		} | ||||
| 		tag := op >> 3 | ||||
| 		wire := op & 7 | ||||
| 
 | ||||
| 		switch wire { | ||||
| 		default: | ||||
| 			fmt.Printf("%3d: t=%3d unknown wire=%d\n", | ||||
| 				index, tag, wire) | ||||
| 			break out | ||||
| 
 | ||||
| 		case WireBytes: | ||||
| 			var r []byte | ||||
| 
 | ||||
| 			r, err = p.DecodeRawBytes(false) | ||||
| 			if err != nil { | ||||
| 				break out | ||||
| 			} | ||||
| 			fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) | ||||
| 			if len(r) <= 6 { | ||||
| 				for i := 0; i < len(r); i++ { | ||||
| 					fmt.Printf(" %.2x", r[i]) | ||||
| 				} | ||||
| 			} else { | ||||
| 				for i := 0; i < 3; i++ { | ||||
| 					fmt.Printf(" %.2x", r[i]) | ||||
| 				} | ||||
| 				fmt.Printf(" ..") | ||||
| 				for i := len(r) - 3; i < len(r); i++ { | ||||
| 					fmt.Printf(" %.2x", r[i]) | ||||
| 				} | ||||
| 			} | ||||
| 			fmt.Printf("\n") | ||||
| 
 | ||||
| 		case WireFixed32: | ||||
| 			u, err = p.DecodeFixed32() | ||||
| 			if err != nil { | ||||
| 				fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) | ||||
| 				break out | ||||
| 			} | ||||
| 			fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) | ||||
| 
 | ||||
| 		case WireFixed64: | ||||
| 			u, err = p.DecodeFixed64() | ||||
| 			if err != nil { | ||||
| 				fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) | ||||
| 				break out | ||||
| 			} | ||||
| 			fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) | ||||
| 
 | ||||
| 		case WireVarint: | ||||
| 			u, err = p.DecodeVarint() | ||||
| 			if err != nil { | ||||
| 				fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) | ||||
| 				break out | ||||
| 			} | ||||
| 			fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) | ||||
| 
 | ||||
| 		case WireStartGroup: | ||||
| 			fmt.Printf("%3d: t=%3d start\n", index, tag) | ||||
| 			depth++ | ||||
| 
 | ||||
| 		case WireEndGroup: | ||||
| 			depth-- | ||||
| 			fmt.Printf("%3d: t=%3d end\n", index, tag) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if depth != 0 { | ||||
| 		fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) | ||||
| 	} | ||||
| 	fmt.Printf("\n") | ||||
| 
 | ||||
| 	p.buf = obuf | ||||
| 	p.index = index | ||||
| } | ||||
| 
 | ||||
| // SetDefaults sets unset protocol buffer fields to their default values.
 | ||||
| // It only modifies fields that are both unset and have defined defaults.
 | ||||
| // It recursively sets default values in any non-nil sub-messages.
 | ||||
| func SetDefaults(pb Message) { | ||||
| 	setDefaults(reflect.ValueOf(pb), true, false) | ||||
| } | ||||
| 
 | ||||
| // v is a pointer to a struct.
 | ||||
| func setDefaults(v reflect.Value, recur, zeros bool) { | ||||
| 	v = v.Elem() | ||||
| 
 | ||||
| 	defaultMu.RLock() | ||||
| 	dm, ok := defaults[v.Type()] | ||||
| 	defaultMu.RUnlock() | ||||
| 	if !ok { | ||||
| 		dm = buildDefaultMessage(v.Type()) | ||||
| 		defaultMu.Lock() | ||||
| 		defaults[v.Type()] = dm | ||||
| 		defaultMu.Unlock() | ||||
| 	} | ||||
| 
 | ||||
| 	for _, sf := range dm.scalars { | ||||
| 		f := v.Field(sf.index) | ||||
| 		if !f.IsNil() { | ||||
| 			// field already set
 | ||||
| 			continue | ||||
| 		} | ||||
| 		dv := sf.value | ||||
| 		if dv == nil && !zeros { | ||||
| 			// no explicit default, and don't want to set zeros
 | ||||
| 			continue | ||||
| 		} | ||||
| 		fptr := f.Addr().Interface() // **T
 | ||||
| 		// TODO: Consider batching the allocations we do here.
 | ||||
| 		switch sf.kind { | ||||
| 		case reflect.Bool: | ||||
| 			b := new(bool) | ||||
| 			if dv != nil { | ||||
| 				*b = dv.(bool) | ||||
| 			} | ||||
| 			*(fptr.(**bool)) = b | ||||
| 		case reflect.Float32: | ||||
| 			f := new(float32) | ||||
| 			if dv != nil { | ||||
| 				*f = dv.(float32) | ||||
| 			} | ||||
| 			*(fptr.(**float32)) = f | ||||
| 		case reflect.Float64: | ||||
| 			f := new(float64) | ||||
| 			if dv != nil { | ||||
| 				*f = dv.(float64) | ||||
| 			} | ||||
| 			*(fptr.(**float64)) = f | ||||
| 		case reflect.Int32: | ||||
| 			// might be an enum
 | ||||
| 			if ft := f.Type(); ft != int32PtrType { | ||||
| 				// enum
 | ||||
| 				f.Set(reflect.New(ft.Elem())) | ||||
| 				if dv != nil { | ||||
| 					f.Elem().SetInt(int64(dv.(int32))) | ||||
| 				} | ||||
| 			} else { | ||||
| 				// int32 field
 | ||||
| 				i := new(int32) | ||||
| 				if dv != nil { | ||||
| 					*i = dv.(int32) | ||||
| 				} | ||||
| 				*(fptr.(**int32)) = i | ||||
| 			} | ||||
| 		case reflect.Int64: | ||||
| 			i := new(int64) | ||||
| 			if dv != nil { | ||||
| 				*i = dv.(int64) | ||||
| 			} | ||||
| 			*(fptr.(**int64)) = i | ||||
| 		case reflect.String: | ||||
| 			s := new(string) | ||||
| 			if dv != nil { | ||||
| 				*s = dv.(string) | ||||
| 			} | ||||
| 			*(fptr.(**string)) = s | ||||
| 		case reflect.Uint8: | ||||
| 			// exceptional case: []byte
 | ||||
| 			var b []byte | ||||
| 			if dv != nil { | ||||
| 				db := dv.([]byte) | ||||
| 				b = make([]byte, len(db)) | ||||
| 				copy(b, db) | ||||
| 			} else { | ||||
| 				b = []byte{} | ||||
| 			} | ||||
| 			*(fptr.(*[]byte)) = b | ||||
| 		case reflect.Uint32: | ||||
| 			u := new(uint32) | ||||
| 			if dv != nil { | ||||
| 				*u = dv.(uint32) | ||||
| 			} | ||||
| 			*(fptr.(**uint32)) = u | ||||
| 		case reflect.Uint64: | ||||
| 			u := new(uint64) | ||||
| 			if dv != nil { | ||||
| 				*u = dv.(uint64) | ||||
| 			} | ||||
| 			*(fptr.(**uint64)) = u | ||||
| 		default: | ||||
| 			log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, ni := range dm.nested { | ||||
| 		f := v.Field(ni) | ||||
| 		// f is *T or []*T or map[T]*T
 | ||||
| 		switch f.Kind() { | ||||
| 		case reflect.Ptr: | ||||
| 			if f.IsNil() { | ||||
| 				continue | ||||
| 			} | ||||
| 			setDefaults(f, recur, zeros) | ||||
| 
 | ||||
| 		case reflect.Slice: | ||||
| 			for i := 0; i < f.Len(); i++ { | ||||
| 				e := f.Index(i) | ||||
| 				if e.IsNil() { | ||||
| 					continue | ||||
| 				} | ||||
| 				setDefaults(e, recur, zeros) | ||||
| 			} | ||||
| 
 | ||||
| 		case reflect.Map: | ||||
| 			for _, k := range f.MapKeys() { | ||||
| 				e := f.MapIndex(k) | ||||
| 				if e.IsNil() { | ||||
| 					continue | ||||
| 				} | ||||
| 				setDefaults(e, recur, zeros) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	// defaults maps a protocol buffer struct type to a slice of the fields,
 | ||||
| 	// with its scalar fields set to their proto-declared non-zero default values.
 | ||||
| 	defaultMu sync.RWMutex | ||||
| 	defaults  = make(map[reflect.Type]defaultMessage) | ||||
| 
 | ||||
| 	int32PtrType = reflect.TypeOf((*int32)(nil)) | ||||
| ) | ||||
| 
 | ||||
| // defaultMessage represents information about the default values of a message.
 | ||||
| type defaultMessage struct { | ||||
| 	scalars []scalarField | ||||
| 	nested  []int // struct field index of nested messages
 | ||||
| } | ||||
| 
 | ||||
| type scalarField struct { | ||||
| 	index int          // struct field index
 | ||||
| 	kind  reflect.Kind // element type (the T in *T or []T)
 | ||||
| 	value interface{}  // the proto-declared default value, or nil
 | ||||
| } | ||||
| 
 | ||||
| // t is a struct type.
 | ||||
| func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { | ||||
| 	sprop := GetProperties(t) | ||||
| 	for _, prop := range sprop.Prop { | ||||
| 		fi, ok := sprop.decoderTags.get(prop.Tag) | ||||
| 		if !ok { | ||||
| 			// XXX_unrecognized
 | ||||
| 			continue | ||||
| 		} | ||||
| 		ft := t.Field(fi).Type | ||||
| 
 | ||||
| 		sf, nested, err := fieldDefault(ft, prop) | ||||
| 		switch { | ||||
| 		case err != nil: | ||||
| 			log.Print(err) | ||||
| 		case nested: | ||||
| 			dm.nested = append(dm.nested, fi) | ||||
| 		case sf != nil: | ||||
| 			sf.index = fi | ||||
| 			dm.scalars = append(dm.scalars, *sf) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return dm | ||||
| } | ||||
| 
 | ||||
| // fieldDefault returns the scalarField for field type ft.
 | ||||
| // sf will be nil if the field can not have a default.
 | ||||
| // nestedMessage will be true if this is a nested message.
 | ||||
| // Note that sf.index is not set on return.
 | ||||
| func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { | ||||
| 	var canHaveDefault bool | ||||
| 	switch ft.Kind() { | ||||
| 	case reflect.Ptr: | ||||
| 		if ft.Elem().Kind() == reflect.Struct { | ||||
| 			nestedMessage = true | ||||
| 		} else { | ||||
| 			canHaveDefault = true // proto2 scalar field
 | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Slice: | ||||
| 		switch ft.Elem().Kind() { | ||||
| 		case reflect.Ptr: | ||||
| 			nestedMessage = true // repeated message
 | ||||
| 		case reflect.Uint8: | ||||
| 			canHaveDefault = true // bytes field
 | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Map: | ||||
| 		if ft.Elem().Kind() == reflect.Ptr { | ||||
| 			nestedMessage = true // map with message values
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if !canHaveDefault { | ||||
| 		if nestedMessage { | ||||
| 			return nil, true, nil | ||||
| 		} | ||||
| 		return nil, false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// We now know that ft is a pointer or slice.
 | ||||
| 	sf = &scalarField{kind: ft.Elem().Kind()} | ||||
| 
 | ||||
| 	// scalar fields without defaults
 | ||||
| 	if !prop.HasDefault { | ||||
| 		return sf, false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// a scalar field: either *T or []byte
 | ||||
| 	switch ft.Elem().Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		x, err := strconv.ParseBool(prop.Default) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = x | ||||
| 	case reflect.Float32: | ||||
| 		x, err := strconv.ParseFloat(prop.Default, 32) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = float32(x) | ||||
| 	case reflect.Float64: | ||||
| 		x, err := strconv.ParseFloat(prop.Default, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = x | ||||
| 	case reflect.Int32: | ||||
| 		x, err := strconv.ParseInt(prop.Default, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = int32(x) | ||||
| 	case reflect.Int64: | ||||
| 		x, err := strconv.ParseInt(prop.Default, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = x | ||||
| 	case reflect.String: | ||||
| 		sf.value = prop.Default | ||||
| 	case reflect.Uint8: | ||||
| 		// []byte (not *uint8)
 | ||||
| 		sf.value = []byte(prop.Default) | ||||
| 	case reflect.Uint32: | ||||
| 		x, err := strconv.ParseUint(prop.Default, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = uint32(x) | ||||
| 	case reflect.Uint64: | ||||
| 		x, err := strconv.ParseUint(prop.Default, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) | ||||
| 		} | ||||
| 		sf.value = x | ||||
| 	default: | ||||
| 		return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) | ||||
| 	} | ||||
| 
 | ||||
| 	return sf, false, nil | ||||
| } | ||||
| 
 | ||||
| // Map fields may have key types of non-float scalars, strings and enums.
 | ||||
| // The easiest way to sort them in some deterministic order is to use fmt.
 | ||||
| // If this turns out to be inefficient we can always consider other options,
 | ||||
| // such as doing a Schwartzian transform.
 | ||||
| 
 | ||||
| func mapKeys(vs []reflect.Value) sort.Interface { | ||||
| 	s := mapKeySorter{ | ||||
| 		vs: vs, | ||||
| 		// default Less function: textual comparison
 | ||||
| 		less: func(a, b reflect.Value) bool { | ||||
| 			return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
 | ||||
| 	// numeric keys are sorted numerically.
 | ||||
| 	if len(vs) == 0 { | ||||
| 		return s | ||||
| 	} | ||||
| 	switch vs[0].Kind() { | ||||
| 	case reflect.Int32, reflect.Int64: | ||||
| 		s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } | ||||
| 	case reflect.Uint32, reflect.Uint64: | ||||
| 		s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } | ||||
| 	} | ||||
| 
 | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| type mapKeySorter struct { | ||||
| 	vs   []reflect.Value | ||||
| 	less func(a, b reflect.Value) bool | ||||
| } | ||||
| 
 | ||||
| func (s mapKeySorter) Len() int      { return len(s.vs) } | ||||
| func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } | ||||
| func (s mapKeySorter) Less(i, j int) bool { | ||||
| 	return s.less(s.vs[i], s.vs[j]) | ||||
| } | ||||
| 
 | ||||
| // isProto3Zero reports whether v is a zero proto3 value.
 | ||||
| func isProto3Zero(v reflect.Value) bool { | ||||
| 	switch v.Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		return !v.Bool() | ||||
| 	case reflect.Int32, reflect.Int64: | ||||
| 		return v.Int() == 0 | ||||
| 	case reflect.Uint32, reflect.Uint64: | ||||
| 		return v.Uint() == 0 | ||||
| 	case reflect.Float32, reflect.Float64: | ||||
| 		return v.Float() == 0 | ||||
| 	case reflect.String: | ||||
| 		return v.String() == "" | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // ProtoPackageIsVersion2 is referenced from generated protocol buffer files
 | ||||
| // to assert that that code is compatible with this version of the proto package.
 | ||||
| const ProtoPackageIsVersion2 = true | ||||
| 
 | ||||
| // ProtoPackageIsVersion1 is referenced from generated protocol buffer files
 | ||||
| // to assert that that code is compatible with this version of the proto package.
 | ||||
| const ProtoPackageIsVersion1 = true | ||||
|  | @ -0,0 +1,311 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| /* | ||||
|  * Support for message sets. | ||||
|  */ | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| ) | ||||
| 
 | ||||
| // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
 | ||||
| // A message type ID is required for storing a protocol buffer in a message set.
 | ||||
| var errNoMessageTypeID = errors.New("proto does not have a message type ID") | ||||
| 
 | ||||
| // The first two types (_MessageSet_Item and messageSet)
 | ||||
| // model what the protocol compiler produces for the following protocol message:
 | ||||
| //   message MessageSet {
 | ||||
| //     repeated group Item = 1 {
 | ||||
| //       required int32 type_id = 2;
 | ||||
| //       required string message = 3;
 | ||||
| //     };
 | ||||
| //   }
 | ||||
| // That is the MessageSet wire format. We can't use a proto to generate these
 | ||||
| // because that would introduce a circular dependency between it and this package.
 | ||||
| 
 | ||||
| type _MessageSet_Item struct { | ||||
| 	TypeId  *int32 `protobuf:"varint,2,req,name=type_id"` | ||||
| 	Message []byte `protobuf:"bytes,3,req,name=message"` | ||||
| } | ||||
| 
 | ||||
| type messageSet struct { | ||||
| 	Item             []*_MessageSet_Item `protobuf:"group,1,rep"` | ||||
| 	XXX_unrecognized []byte | ||||
| 	// TODO: caching?
 | ||||
| } | ||||
| 
 | ||||
| // Make sure messageSet is a Message.
 | ||||
| var _ Message = (*messageSet)(nil) | ||||
| 
 | ||||
| // messageTypeIder is an interface satisfied by a protocol buffer type
 | ||||
| // that may be stored in a MessageSet.
 | ||||
| type messageTypeIder interface { | ||||
| 	MessageTypeId() int32 | ||||
| } | ||||
| 
 | ||||
| func (ms *messageSet) find(pb Message) *_MessageSet_Item { | ||||
| 	mti, ok := pb.(messageTypeIder) | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	id := mti.MessageTypeId() | ||||
| 	for _, item := range ms.Item { | ||||
| 		if *item.TypeId == id { | ||||
| 			return item | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ms *messageSet) Has(pb Message) bool { | ||||
| 	if ms.find(pb) != nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (ms *messageSet) Unmarshal(pb Message) error { | ||||
| 	if item := ms.find(pb); item != nil { | ||||
| 		return Unmarshal(item.Message, pb) | ||||
| 	} | ||||
| 	if _, ok := pb.(messageTypeIder); !ok { | ||||
| 		return errNoMessageTypeID | ||||
| 	} | ||||
| 	return nil // TODO: return error instead?
 | ||||
| } | ||||
| 
 | ||||
| func (ms *messageSet) Marshal(pb Message) error { | ||||
| 	msg, err := Marshal(pb) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if item := ms.find(pb); item != nil { | ||||
| 		// reuse existing item
 | ||||
| 		item.Message = msg | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	mti, ok := pb.(messageTypeIder) | ||||
| 	if !ok { | ||||
| 		return errNoMessageTypeID | ||||
| 	} | ||||
| 
 | ||||
| 	mtid := mti.MessageTypeId() | ||||
| 	ms.Item = append(ms.Item, &_MessageSet_Item{ | ||||
| 		TypeId:  &mtid, | ||||
| 		Message: msg, | ||||
| 	}) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ms *messageSet) Reset()         { *ms = messageSet{} } | ||||
| func (ms *messageSet) String() string { return CompactTextString(ms) } | ||||
| func (*messageSet) ProtoMessage()     {} | ||||
| 
 | ||||
| // Support for the message_set_wire_format message option.
 | ||||
| 
 | ||||
| func skipVarint(buf []byte) []byte { | ||||
| 	i := 0 | ||||
| 	for ; buf[i]&0x80 != 0; i++ { | ||||
| 	} | ||||
| 	return buf[i+1:] | ||||
| } | ||||
| 
 | ||||
| // MarshalMessageSet encodes the extension map represented by m in the message set wire format.
 | ||||
| // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
 | ||||
| func MarshalMessageSet(exts interface{}) ([]byte, error) { | ||||
| 	var m map[int32]Extension | ||||
| 	switch exts := exts.(type) { | ||||
| 	case *XXX_InternalExtensions: | ||||
| 		if err := encodeExtensions(exts); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m, _ = exts.extensionsRead() | ||||
| 	case map[int32]Extension: | ||||
| 		if err := encodeExtensionsMap(exts); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m = exts | ||||
| 	default: | ||||
| 		return nil, errors.New("proto: not an extension map") | ||||
| 	} | ||||
| 
 | ||||
| 	// Sort extension IDs to provide a deterministic encoding.
 | ||||
| 	// See also enc_map in encode.go.
 | ||||
| 	ids := make([]int, 0, len(m)) | ||||
| 	for id := range m { | ||||
| 		ids = append(ids, int(id)) | ||||
| 	} | ||||
| 	sort.Ints(ids) | ||||
| 
 | ||||
| 	ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} | ||||
| 	for _, id := range ids { | ||||
| 		e := m[int32(id)] | ||||
| 		// Remove the wire type and field number varint, as well as the length varint.
 | ||||
| 		msg := skipVarint(skipVarint(e.enc)) | ||||
| 
 | ||||
| 		ms.Item = append(ms.Item, &_MessageSet_Item{ | ||||
| 			TypeId:  Int32(int32(id)), | ||||
| 			Message: msg, | ||||
| 		}) | ||||
| 	} | ||||
| 	return Marshal(ms) | ||||
| } | ||||
| 
 | ||||
| // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
 | ||||
| // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
 | ||||
| func UnmarshalMessageSet(buf []byte, exts interface{}) error { | ||||
| 	var m map[int32]Extension | ||||
| 	switch exts := exts.(type) { | ||||
| 	case *XXX_InternalExtensions: | ||||
| 		m = exts.extensionsWrite() | ||||
| 	case map[int32]Extension: | ||||
| 		m = exts | ||||
| 	default: | ||||
| 		return errors.New("proto: not an extension map") | ||||
| 	} | ||||
| 
 | ||||
| 	ms := new(messageSet) | ||||
| 	if err := Unmarshal(buf, ms); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, item := range ms.Item { | ||||
| 		id := *item.TypeId | ||||
| 		msg := item.Message | ||||
| 
 | ||||
| 		// Restore wire type and field number varint, plus length varint.
 | ||||
| 		// Be careful to preserve duplicate items.
 | ||||
| 		b := EncodeVarint(uint64(id)<<3 | WireBytes) | ||||
| 		if ext, ok := m[id]; ok { | ||||
| 			// Existing data; rip off the tag and length varint
 | ||||
| 			// so we join the new data correctly.
 | ||||
| 			// We can assume that ext.enc is set because we are unmarshaling.
 | ||||
| 			o := ext.enc[len(b):]   // skip wire type and field number
 | ||||
| 			_, n := DecodeVarint(o) // calculate length of length varint
 | ||||
| 			o = o[n:]               // skip length varint
 | ||||
| 			msg = append(o, msg...) // join old data and new data
 | ||||
| 		} | ||||
| 		b = append(b, EncodeVarint(uint64(len(msg)))...) | ||||
| 		b = append(b, msg...) | ||||
| 
 | ||||
| 		m[id] = Extension{enc: b} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
 | ||||
| // It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
 | ||||
| func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { | ||||
| 	var m map[int32]Extension | ||||
| 	switch exts := exts.(type) { | ||||
| 	case *XXX_InternalExtensions: | ||||
| 		m, _ = exts.extensionsRead() | ||||
| 	case map[int32]Extension: | ||||
| 		m = exts | ||||
| 	default: | ||||
| 		return nil, errors.New("proto: not an extension map") | ||||
| 	} | ||||
| 	var b bytes.Buffer | ||||
| 	b.WriteByte('{') | ||||
| 
 | ||||
| 	// Process the map in key order for deterministic output.
 | ||||
| 	ids := make([]int32, 0, len(m)) | ||||
| 	for id := range m { | ||||
| 		ids = append(ids, id) | ||||
| 	} | ||||
| 	sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
 | ||||
| 
 | ||||
| 	for i, id := range ids { | ||||
| 		ext := m[id] | ||||
| 		if i > 0 { | ||||
| 			b.WriteByte(',') | ||||
| 		} | ||||
| 
 | ||||
| 		msd, ok := messageSetMap[id] | ||||
| 		if !ok { | ||||
| 			// Unknown type; we can't render it, so skip it.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		fmt.Fprintf(&b, `"[%s]":`, msd.name) | ||||
| 
 | ||||
| 		x := ext.value | ||||
| 		if x == nil { | ||||
| 			x = reflect.New(msd.t.Elem()).Interface() | ||||
| 			if err := Unmarshal(ext.enc, x.(Message)); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
| 		d, err := json.Marshal(x) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		b.Write(d) | ||||
| 	} | ||||
| 	b.WriteByte('}') | ||||
| 	return b.Bytes(), nil | ||||
| } | ||||
| 
 | ||||
| // UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
 | ||||
| // It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
 | ||||
| func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { | ||||
| 	// Common-case fast path.
 | ||||
| 	if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// This is fairly tricky, and it's not clear that it is needed.
 | ||||
| 	return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") | ||||
| } | ||||
| 
 | ||||
| // A global registry of types that can be used in a MessageSet.
 | ||||
| 
 | ||||
| var messageSetMap = make(map[int32]messageSetDesc) | ||||
| 
 | ||||
| type messageSetDesc struct { | ||||
| 	t    reflect.Type // pointer to struct
 | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| // RegisterMessageSetType is called from the generated code.
 | ||||
| func RegisterMessageSetType(m Message, fieldNum int32, name string) { | ||||
| 	messageSetMap[fieldNum] = messageSetDesc{ | ||||
| 		t:    reflect.TypeOf(m), | ||||
| 		name: name, | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,484 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2012 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| // +build appengine js
 | ||||
| 
 | ||||
| // This file contains an implementation of proto field accesses using package reflect.
 | ||||
| // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
 | ||||
| // be used on App Engine.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| ) | ||||
| 
 | ||||
| // A structPointer is a pointer to a struct.
 | ||||
| type structPointer struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| // toStructPointer returns a structPointer equivalent to the given reflect value.
 | ||||
| // The reflect value must itself be a pointer to a struct.
 | ||||
| func toStructPointer(v reflect.Value) structPointer { | ||||
| 	return structPointer{v} | ||||
| } | ||||
| 
 | ||||
| // IsNil reports whether p is nil.
 | ||||
| func structPointer_IsNil(p structPointer) bool { | ||||
| 	return p.v.IsNil() | ||||
| } | ||||
| 
 | ||||
| // Interface returns the struct pointer as an interface value.
 | ||||
| func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { | ||||
| 	return p.v.Interface() | ||||
| } | ||||
| 
 | ||||
| // A field identifies a field in a struct, accessible from a structPointer.
 | ||||
| // In this implementation, a field is identified by the sequence of field indices
 | ||||
| // passed to reflect's FieldByIndex.
 | ||||
| type field []int | ||||
| 
 | ||||
| // toField returns a field equivalent to the given reflect field.
 | ||||
| func toField(f *reflect.StructField) field { | ||||
| 	return f.Index | ||||
| } | ||||
| 
 | ||||
| // invalidField is an invalid field identifier.
 | ||||
| var invalidField = field(nil) | ||||
| 
 | ||||
| // IsValid reports whether the field identifier is valid.
 | ||||
| func (f field) IsValid() bool { return f != nil } | ||||
| 
 | ||||
| // field returns the given field in the struct as a reflect value.
 | ||||
| func structPointer_field(p structPointer, f field) reflect.Value { | ||||
| 	// Special case: an extension map entry with a value of type T
 | ||||
| 	// passes a *T to the struct-handling code with a zero field,
 | ||||
| 	// expecting that it will be treated as equivalent to *struct{ X T },
 | ||||
| 	// which has the same memory layout. We have to handle that case
 | ||||
| 	// specially, because reflect will panic if we call FieldByIndex on a
 | ||||
| 	// non-struct.
 | ||||
| 	if f == nil { | ||||
| 		return p.v.Elem() | ||||
| 	} | ||||
| 
 | ||||
| 	return p.v.Elem().FieldByIndex(f) | ||||
| } | ||||
| 
 | ||||
| // ifield returns the given field in the struct as an interface value.
 | ||||
| func structPointer_ifield(p structPointer, f field) interface{} { | ||||
| 	return structPointer_field(p, f).Addr().Interface() | ||||
| } | ||||
| 
 | ||||
| // Bytes returns the address of a []byte field in the struct.
 | ||||
| func structPointer_Bytes(p structPointer, f field) *[]byte { | ||||
| 	return structPointer_ifield(p, f).(*[]byte) | ||||
| } | ||||
| 
 | ||||
| // BytesSlice returns the address of a [][]byte field in the struct.
 | ||||
| func structPointer_BytesSlice(p structPointer, f field) *[][]byte { | ||||
| 	return structPointer_ifield(p, f).(*[][]byte) | ||||
| } | ||||
| 
 | ||||
| // Bool returns the address of a *bool field in the struct.
 | ||||
| func structPointer_Bool(p structPointer, f field) **bool { | ||||
| 	return structPointer_ifield(p, f).(**bool) | ||||
| } | ||||
| 
 | ||||
| // BoolVal returns the address of a bool field in the struct.
 | ||||
| func structPointer_BoolVal(p structPointer, f field) *bool { | ||||
| 	return structPointer_ifield(p, f).(*bool) | ||||
| } | ||||
| 
 | ||||
| // BoolSlice returns the address of a []bool field in the struct.
 | ||||
| func structPointer_BoolSlice(p structPointer, f field) *[]bool { | ||||
| 	return structPointer_ifield(p, f).(*[]bool) | ||||
| } | ||||
| 
 | ||||
| // String returns the address of a *string field in the struct.
 | ||||
| func structPointer_String(p structPointer, f field) **string { | ||||
| 	return structPointer_ifield(p, f).(**string) | ||||
| } | ||||
| 
 | ||||
| // StringVal returns the address of a string field in the struct.
 | ||||
| func structPointer_StringVal(p structPointer, f field) *string { | ||||
| 	return structPointer_ifield(p, f).(*string) | ||||
| } | ||||
| 
 | ||||
| // StringSlice returns the address of a []string field in the struct.
 | ||||
| func structPointer_StringSlice(p structPointer, f field) *[]string { | ||||
| 	return structPointer_ifield(p, f).(*[]string) | ||||
| } | ||||
| 
 | ||||
| // Extensions returns the address of an extension map field in the struct.
 | ||||
| func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { | ||||
| 	return structPointer_ifield(p, f).(*XXX_InternalExtensions) | ||||
| } | ||||
| 
 | ||||
| // ExtMap returns the address of an extension map field in the struct.
 | ||||
| func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { | ||||
| 	return structPointer_ifield(p, f).(*map[int32]Extension) | ||||
| } | ||||
| 
 | ||||
| // NewAt returns the reflect.Value for a pointer to a field in the struct.
 | ||||
| func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { | ||||
| 	return structPointer_field(p, f).Addr() | ||||
| } | ||||
| 
 | ||||
| // SetStructPointer writes a *struct field in the struct.
 | ||||
| func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { | ||||
| 	structPointer_field(p, f).Set(q.v) | ||||
| } | ||||
| 
 | ||||
| // GetStructPointer reads a *struct field in the struct.
 | ||||
| func structPointer_GetStructPointer(p structPointer, f field) structPointer { | ||||
| 	return structPointer{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| // StructPointerSlice the address of a []*struct field in the struct.
 | ||||
| func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { | ||||
| 	return structPointerSlice{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| // A structPointerSlice represents the address of a slice of pointers to structs
 | ||||
| // (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
 | ||||
| type structPointerSlice struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| func (p structPointerSlice) Len() int                  { return p.v.Len() } | ||||
| func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } | ||||
| func (p structPointerSlice) Append(q structPointer) { | ||||
| 	p.v.Set(reflect.Append(p.v, q.v)) | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	int32Type   = reflect.TypeOf(int32(0)) | ||||
| 	uint32Type  = reflect.TypeOf(uint32(0)) | ||||
| 	float32Type = reflect.TypeOf(float32(0)) | ||||
| 	int64Type   = reflect.TypeOf(int64(0)) | ||||
| 	uint64Type  = reflect.TypeOf(uint64(0)) | ||||
| 	float64Type = reflect.TypeOf(float64(0)) | ||||
| ) | ||||
| 
 | ||||
| // A word32 represents a field of type *int32, *uint32, *float32, or *enum.
 | ||||
| // That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
 | ||||
| type word32 struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| // IsNil reports whether p is nil.
 | ||||
| func word32_IsNil(p word32) bool { | ||||
| 	return p.v.IsNil() | ||||
| } | ||||
| 
 | ||||
| // Set sets p to point at a newly allocated word with bits set to x.
 | ||||
| func word32_Set(p word32, o *Buffer, x uint32) { | ||||
| 	t := p.v.Type().Elem() | ||||
| 	switch t { | ||||
| 	case int32Type: | ||||
| 		if len(o.int32s) == 0 { | ||||
| 			o.int32s = make([]int32, uint32PoolSize) | ||||
| 		} | ||||
| 		o.int32s[0] = int32(x) | ||||
| 		p.v.Set(reflect.ValueOf(&o.int32s[0])) | ||||
| 		o.int32s = o.int32s[1:] | ||||
| 		return | ||||
| 	case uint32Type: | ||||
| 		if len(o.uint32s) == 0 { | ||||
| 			o.uint32s = make([]uint32, uint32PoolSize) | ||||
| 		} | ||||
| 		o.uint32s[0] = x | ||||
| 		p.v.Set(reflect.ValueOf(&o.uint32s[0])) | ||||
| 		o.uint32s = o.uint32s[1:] | ||||
| 		return | ||||
| 	case float32Type: | ||||
| 		if len(o.float32s) == 0 { | ||||
| 			o.float32s = make([]float32, uint32PoolSize) | ||||
| 		} | ||||
| 		o.float32s[0] = math.Float32frombits(x) | ||||
| 		p.v.Set(reflect.ValueOf(&o.float32s[0])) | ||||
| 		o.float32s = o.float32s[1:] | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// must be enum
 | ||||
| 	p.v.Set(reflect.New(t)) | ||||
| 	p.v.Elem().SetInt(int64(int32(x))) | ||||
| } | ||||
| 
 | ||||
| // Get gets the bits pointed at by p, as a uint32.
 | ||||
| func word32_Get(p word32) uint32 { | ||||
| 	elem := p.v.Elem() | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int32: | ||||
| 		return uint32(elem.Int()) | ||||
| 	case reflect.Uint32: | ||||
| 		return uint32(elem.Uint()) | ||||
| 	case reflect.Float32: | ||||
| 		return math.Float32bits(float32(elem.Float())) | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| // Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
 | ||||
| func structPointer_Word32(p structPointer, f field) word32 { | ||||
| 	return word32{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| // A word32Val represents a field of type int32, uint32, float32, or enum.
 | ||||
| // That is, v.Type() is int32, uint32, float32, or enum and v is assignable.
 | ||||
| type word32Val struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| // Set sets *p to x.
 | ||||
| func word32Val_Set(p word32Val, x uint32) { | ||||
| 	switch p.v.Type() { | ||||
| 	case int32Type: | ||||
| 		p.v.SetInt(int64(x)) | ||||
| 		return | ||||
| 	case uint32Type: | ||||
| 		p.v.SetUint(uint64(x)) | ||||
| 		return | ||||
| 	case float32Type: | ||||
| 		p.v.SetFloat(float64(math.Float32frombits(x))) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// must be enum
 | ||||
| 	p.v.SetInt(int64(int32(x))) | ||||
| } | ||||
| 
 | ||||
| // Get gets the bits pointed at by p, as a uint32.
 | ||||
| func word32Val_Get(p word32Val) uint32 { | ||||
| 	elem := p.v | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int32: | ||||
| 		return uint32(elem.Int()) | ||||
| 	case reflect.Uint32: | ||||
| 		return uint32(elem.Uint()) | ||||
| 	case reflect.Float32: | ||||
| 		return math.Float32bits(float32(elem.Float())) | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| // Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct.
 | ||||
| func structPointer_Word32Val(p structPointer, f field) word32Val { | ||||
| 	return word32Val{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| // A word32Slice is a slice of 32-bit values.
 | ||||
| // That is, v.Type() is []int32, []uint32, []float32, or []enum.
 | ||||
| type word32Slice struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| func (p word32Slice) Append(x uint32) { | ||||
| 	n, m := p.v.Len(), p.v.Cap() | ||||
| 	if n < m { | ||||
| 		p.v.SetLen(n + 1) | ||||
| 	} else { | ||||
| 		t := p.v.Type().Elem() | ||||
| 		p.v.Set(reflect.Append(p.v, reflect.Zero(t))) | ||||
| 	} | ||||
| 	elem := p.v.Index(n) | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int32: | ||||
| 		elem.SetInt(int64(int32(x))) | ||||
| 	case reflect.Uint32: | ||||
| 		elem.SetUint(uint64(x)) | ||||
| 	case reflect.Float32: | ||||
| 		elem.SetFloat(float64(math.Float32frombits(x))) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (p word32Slice) Len() int { | ||||
| 	return p.v.Len() | ||||
| } | ||||
| 
 | ||||
| func (p word32Slice) Index(i int) uint32 { | ||||
| 	elem := p.v.Index(i) | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int32: | ||||
| 		return uint32(elem.Int()) | ||||
| 	case reflect.Uint32: | ||||
| 		return uint32(elem.Uint()) | ||||
| 	case reflect.Float32: | ||||
| 		return math.Float32bits(float32(elem.Float())) | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| // Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
 | ||||
| func structPointer_Word32Slice(p structPointer, f field) word32Slice { | ||||
| 	return word32Slice{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| // word64 is like word32 but for 64-bit values.
 | ||||
| type word64 struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| func word64_Set(p word64, o *Buffer, x uint64) { | ||||
| 	t := p.v.Type().Elem() | ||||
| 	switch t { | ||||
| 	case int64Type: | ||||
| 		if len(o.int64s) == 0 { | ||||
| 			o.int64s = make([]int64, uint64PoolSize) | ||||
| 		} | ||||
| 		o.int64s[0] = int64(x) | ||||
| 		p.v.Set(reflect.ValueOf(&o.int64s[0])) | ||||
| 		o.int64s = o.int64s[1:] | ||||
| 		return | ||||
| 	case uint64Type: | ||||
| 		if len(o.uint64s) == 0 { | ||||
| 			o.uint64s = make([]uint64, uint64PoolSize) | ||||
| 		} | ||||
| 		o.uint64s[0] = x | ||||
| 		p.v.Set(reflect.ValueOf(&o.uint64s[0])) | ||||
| 		o.uint64s = o.uint64s[1:] | ||||
| 		return | ||||
| 	case float64Type: | ||||
| 		if len(o.float64s) == 0 { | ||||
| 			o.float64s = make([]float64, uint64PoolSize) | ||||
| 		} | ||||
| 		o.float64s[0] = math.Float64frombits(x) | ||||
| 		p.v.Set(reflect.ValueOf(&o.float64s[0])) | ||||
| 		o.float64s = o.float64s[1:] | ||||
| 		return | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| func word64_IsNil(p word64) bool { | ||||
| 	return p.v.IsNil() | ||||
| } | ||||
| 
 | ||||
| func word64_Get(p word64) uint64 { | ||||
| 	elem := p.v.Elem() | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int64: | ||||
| 		return uint64(elem.Int()) | ||||
| 	case reflect.Uint64: | ||||
| 		return elem.Uint() | ||||
| 	case reflect.Float64: | ||||
| 		return math.Float64bits(elem.Float()) | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| func structPointer_Word64(p structPointer, f field) word64 { | ||||
| 	return word64{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| // word64Val is like word32Val but for 64-bit values.
 | ||||
| type word64Val struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| func word64Val_Set(p word64Val, o *Buffer, x uint64) { | ||||
| 	switch p.v.Type() { | ||||
| 	case int64Type: | ||||
| 		p.v.SetInt(int64(x)) | ||||
| 		return | ||||
| 	case uint64Type: | ||||
| 		p.v.SetUint(x) | ||||
| 		return | ||||
| 	case float64Type: | ||||
| 		p.v.SetFloat(math.Float64frombits(x)) | ||||
| 		return | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| func word64Val_Get(p word64Val) uint64 { | ||||
| 	elem := p.v | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int64: | ||||
| 		return uint64(elem.Int()) | ||||
| 	case reflect.Uint64: | ||||
| 		return elem.Uint() | ||||
| 	case reflect.Float64: | ||||
| 		return math.Float64bits(elem.Float()) | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| func structPointer_Word64Val(p structPointer, f field) word64Val { | ||||
| 	return word64Val{structPointer_field(p, f)} | ||||
| } | ||||
| 
 | ||||
| type word64Slice struct { | ||||
| 	v reflect.Value | ||||
| } | ||||
| 
 | ||||
| func (p word64Slice) Append(x uint64) { | ||||
| 	n, m := p.v.Len(), p.v.Cap() | ||||
| 	if n < m { | ||||
| 		p.v.SetLen(n + 1) | ||||
| 	} else { | ||||
| 		t := p.v.Type().Elem() | ||||
| 		p.v.Set(reflect.Append(p.v, reflect.Zero(t))) | ||||
| 	} | ||||
| 	elem := p.v.Index(n) | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int64: | ||||
| 		elem.SetInt(int64(int64(x))) | ||||
| 	case reflect.Uint64: | ||||
| 		elem.SetUint(uint64(x)) | ||||
| 	case reflect.Float64: | ||||
| 		elem.SetFloat(float64(math.Float64frombits(x))) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (p word64Slice) Len() int { | ||||
| 	return p.v.Len() | ||||
| } | ||||
| 
 | ||||
| func (p word64Slice) Index(i int) uint64 { | ||||
| 	elem := p.v.Index(i) | ||||
| 	switch elem.Kind() { | ||||
| 	case reflect.Int64: | ||||
| 		return uint64(elem.Int()) | ||||
| 	case reflect.Uint64: | ||||
| 		return uint64(elem.Uint()) | ||||
| 	case reflect.Float64: | ||||
| 		return math.Float64bits(float64(elem.Float())) | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| func structPointer_Word64Slice(p structPointer, f field) word64Slice { | ||||
| 	return word64Slice{structPointer_field(p, f)} | ||||
| } | ||||
|  | @ -0,0 +1,270 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2012 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| // +build !appengine,!js
 | ||||
| 
 | ||||
| // This file contains the implementation of the proto field accesses using package unsafe.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| // NOTE: These type_Foo functions would more idiomatically be methods,
 | ||||
| // but Go does not allow methods on pointer types, and we must preserve
 | ||||
| // some pointer type for the garbage collector. We use these
 | ||||
| // funcs with clunky names as our poor approximation to methods.
 | ||||
| //
 | ||||
| // An alternative would be
 | ||||
| //	type structPointer struct { p unsafe.Pointer }
 | ||||
| // but that does not registerize as well.
 | ||||
| 
 | ||||
| // A structPointer is a pointer to a struct.
 | ||||
| type structPointer unsafe.Pointer | ||||
| 
 | ||||
| // toStructPointer returns a structPointer equivalent to the given reflect value.
 | ||||
| func toStructPointer(v reflect.Value) structPointer { | ||||
| 	return structPointer(unsafe.Pointer(v.Pointer())) | ||||
| } | ||||
| 
 | ||||
| // IsNil reports whether p is nil.
 | ||||
| func structPointer_IsNil(p structPointer) bool { | ||||
| 	return p == nil | ||||
| } | ||||
| 
 | ||||
| // Interface returns the struct pointer, assumed to have element type t,
 | ||||
| // as an interface value.
 | ||||
| func structPointer_Interface(p structPointer, t reflect.Type) interface{} { | ||||
| 	return reflect.NewAt(t, unsafe.Pointer(p)).Interface() | ||||
| } | ||||
| 
 | ||||
| // A field identifies a field in a struct, accessible from a structPointer.
 | ||||
| // In this implementation, a field is identified by its byte offset from the start of the struct.
 | ||||
| type field uintptr | ||||
| 
 | ||||
| // toField returns a field equivalent to the given reflect field.
 | ||||
| func toField(f *reflect.StructField) field { | ||||
| 	return field(f.Offset) | ||||
| } | ||||
| 
 | ||||
| // invalidField is an invalid field identifier.
 | ||||
| const invalidField = ^field(0) | ||||
| 
 | ||||
| // IsValid reports whether the field identifier is valid.
 | ||||
| func (f field) IsValid() bool { | ||||
| 	return f != ^field(0) | ||||
| } | ||||
| 
 | ||||
| // Bytes returns the address of a []byte field in the struct.
 | ||||
| func structPointer_Bytes(p structPointer, f field) *[]byte { | ||||
| 	return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // BytesSlice returns the address of a [][]byte field in the struct.
 | ||||
| func structPointer_BytesSlice(p structPointer, f field) *[][]byte { | ||||
| 	return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // Bool returns the address of a *bool field in the struct.
 | ||||
| func structPointer_Bool(p structPointer, f field) **bool { | ||||
| 	return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // BoolVal returns the address of a bool field in the struct.
 | ||||
| func structPointer_BoolVal(p structPointer, f field) *bool { | ||||
| 	return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // BoolSlice returns the address of a []bool field in the struct.
 | ||||
| func structPointer_BoolSlice(p structPointer, f field) *[]bool { | ||||
| 	return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // String returns the address of a *string field in the struct.
 | ||||
| func structPointer_String(p structPointer, f field) **string { | ||||
| 	return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // StringVal returns the address of a string field in the struct.
 | ||||
| func structPointer_StringVal(p structPointer, f field) *string { | ||||
| 	return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // StringSlice returns the address of a []string field in the struct.
 | ||||
| func structPointer_StringSlice(p structPointer, f field) *[]string { | ||||
| 	return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // ExtMap returns the address of an extension map field in the struct.
 | ||||
| func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { | ||||
| 	return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { | ||||
| 	return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // NewAt returns the reflect.Value for a pointer to a field in the struct.
 | ||||
| func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { | ||||
| 	return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // SetStructPointer writes a *struct field in the struct.
 | ||||
| func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { | ||||
| 	*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q | ||||
| } | ||||
| 
 | ||||
| // GetStructPointer reads a *struct field in the struct.
 | ||||
| func structPointer_GetStructPointer(p structPointer, f field) structPointer { | ||||
| 	return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // StructPointerSlice the address of a []*struct field in the struct.
 | ||||
| func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { | ||||
| 	return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
 | ||||
| type structPointerSlice []structPointer | ||||
| 
 | ||||
| func (v *structPointerSlice) Len() int                  { return len(*v) } | ||||
| func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } | ||||
| func (v *structPointerSlice) Append(p structPointer)    { *v = append(*v, p) } | ||||
| 
 | ||||
| // A word32 is the address of a "pointer to 32-bit value" field.
 | ||||
| type word32 **uint32 | ||||
| 
 | ||||
| // IsNil reports whether *v is nil.
 | ||||
| func word32_IsNil(p word32) bool { | ||||
| 	return *p == nil | ||||
| } | ||||
| 
 | ||||
| // Set sets *v to point at a newly allocated word set to x.
 | ||||
| func word32_Set(p word32, o *Buffer, x uint32) { | ||||
| 	if len(o.uint32s) == 0 { | ||||
| 		o.uint32s = make([]uint32, uint32PoolSize) | ||||
| 	} | ||||
| 	o.uint32s[0] = x | ||||
| 	*p = &o.uint32s[0] | ||||
| 	o.uint32s = o.uint32s[1:] | ||||
| } | ||||
| 
 | ||||
| // Get gets the value pointed at by *v.
 | ||||
| func word32_Get(p word32) uint32 { | ||||
| 	return **p | ||||
| } | ||||
| 
 | ||||
| // Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
 | ||||
| func structPointer_Word32(p structPointer, f field) word32 { | ||||
| 	return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) | ||||
| } | ||||
| 
 | ||||
| // A word32Val is the address of a 32-bit value field.
 | ||||
| type word32Val *uint32 | ||||
| 
 | ||||
| // Set sets *p to x.
 | ||||
| func word32Val_Set(p word32Val, x uint32) { | ||||
| 	*p = x | ||||
| } | ||||
| 
 | ||||
| // Get gets the value pointed at by p.
 | ||||
| func word32Val_Get(p word32Val) uint32 { | ||||
| 	return *p | ||||
| } | ||||
| 
 | ||||
| // Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
 | ||||
| func structPointer_Word32Val(p structPointer, f field) word32Val { | ||||
| 	return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) | ||||
| } | ||||
| 
 | ||||
| // A word32Slice is a slice of 32-bit values.
 | ||||
| type word32Slice []uint32 | ||||
| 
 | ||||
| func (v *word32Slice) Append(x uint32)    { *v = append(*v, x) } | ||||
| func (v *word32Slice) Len() int           { return len(*v) } | ||||
| func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } | ||||
| 
 | ||||
| // Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
 | ||||
| func structPointer_Word32Slice(p structPointer, f field) *word32Slice { | ||||
| 	return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
| 
 | ||||
| // word64 is like word32 but for 64-bit values.
 | ||||
| type word64 **uint64 | ||||
| 
 | ||||
| func word64_Set(p word64, o *Buffer, x uint64) { | ||||
| 	if len(o.uint64s) == 0 { | ||||
| 		o.uint64s = make([]uint64, uint64PoolSize) | ||||
| 	} | ||||
| 	o.uint64s[0] = x | ||||
| 	*p = &o.uint64s[0] | ||||
| 	o.uint64s = o.uint64s[1:] | ||||
| } | ||||
| 
 | ||||
| func word64_IsNil(p word64) bool { | ||||
| 	return *p == nil | ||||
| } | ||||
| 
 | ||||
| func word64_Get(p word64) uint64 { | ||||
| 	return **p | ||||
| } | ||||
| 
 | ||||
| func structPointer_Word64(p structPointer, f field) word64 { | ||||
| 	return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) | ||||
| } | ||||
| 
 | ||||
| // word64Val is like word32Val but for 64-bit values.
 | ||||
| type word64Val *uint64 | ||||
| 
 | ||||
| func word64Val_Set(p word64Val, o *Buffer, x uint64) { | ||||
| 	*p = x | ||||
| } | ||||
| 
 | ||||
| func word64Val_Get(p word64Val) uint64 { | ||||
| 	return *p | ||||
| } | ||||
| 
 | ||||
| func structPointer_Word64Val(p structPointer, f field) word64Val { | ||||
| 	return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) | ||||
| } | ||||
| 
 | ||||
| // word64Slice is like word32Slice but for 64-bit values.
 | ||||
| type word64Slice []uint64 | ||||
| 
 | ||||
| func (v *word64Slice) Append(x uint64)    { *v = append(*v, x) } | ||||
| func (v *word64Slice) Len() int           { return len(*v) } | ||||
| func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } | ||||
| 
 | ||||
| func structPointer_Word64Slice(p structPointer, f field) *word64Slice { | ||||
| 	return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) | ||||
| } | ||||
|  | @ -0,0 +1,872 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| /* | ||||
|  * Routines for encoding data into the wire format for protocol buffers. | ||||
|  */ | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| const debug bool = false | ||||
| 
 | ||||
| // Constants that identify the encoding of a value on the wire.
 | ||||
| const ( | ||||
| 	WireVarint     = 0 | ||||
| 	WireFixed64    = 1 | ||||
| 	WireBytes      = 2 | ||||
| 	WireStartGroup = 3 | ||||
| 	WireEndGroup   = 4 | ||||
| 	WireFixed32    = 5 | ||||
| ) | ||||
| 
 | ||||
| const startSize = 10 // initial slice/string sizes
 | ||||
| 
 | ||||
| // Encoders are defined in encode.go
 | ||||
| // An encoder outputs the full representation of a field, including its
 | ||||
| // tag and encoder type.
 | ||||
| type encoder func(p *Buffer, prop *Properties, base structPointer) error | ||||
| 
 | ||||
| // A valueEncoder encodes a single integer in a particular encoding.
 | ||||
| type valueEncoder func(o *Buffer, x uint64) error | ||||
| 
 | ||||
| // Sizers are defined in encode.go
 | ||||
| // A sizer returns the encoded size of a field, including its tag and encoder
 | ||||
| // type.
 | ||||
| type sizer func(prop *Properties, base structPointer) int | ||||
| 
 | ||||
| // A valueSizer returns the encoded size of a single integer in a particular
 | ||||
| // encoding.
 | ||||
| type valueSizer func(x uint64) int | ||||
| 
 | ||||
| // Decoders are defined in decode.go
 | ||||
| // A decoder creates a value from its wire representation.
 | ||||
| // Unrecognized subelements are saved in unrec.
 | ||||
| type decoder func(p *Buffer, prop *Properties, base structPointer) error | ||||
| 
 | ||||
| // A valueDecoder decodes a single integer in a particular encoding.
 | ||||
| type valueDecoder func(o *Buffer) (x uint64, err error) | ||||
| 
 | ||||
| // A oneofMarshaler does the marshaling for all oneof fields in a message.
 | ||||
| type oneofMarshaler func(Message, *Buffer) error | ||||
| 
 | ||||
| // A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
 | ||||
| type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) | ||||
| 
 | ||||
| // A oneofSizer does the sizing for all oneof fields in a message.
 | ||||
| type oneofSizer func(Message) int | ||||
| 
 | ||||
| // tagMap is an optimization over map[int]int for typical protocol buffer
 | ||||
| // use-cases. Encoded protocol buffers are often in tag order with small tag
 | ||||
| // numbers.
 | ||||
| type tagMap struct { | ||||
| 	fastTags []int | ||||
| 	slowTags map[int]int | ||||
| } | ||||
| 
 | ||||
| // tagMapFastLimit is the upper bound on the tag number that will be stored in
 | ||||
| // the tagMap slice rather than its map.
 | ||||
| const tagMapFastLimit = 1024 | ||||
| 
 | ||||
| func (p *tagMap) get(t int) (int, bool) { | ||||
| 	if t > 0 && t < tagMapFastLimit { | ||||
| 		if t >= len(p.fastTags) { | ||||
| 			return 0, false | ||||
| 		} | ||||
| 		fi := p.fastTags[t] | ||||
| 		return fi, fi >= 0 | ||||
| 	} | ||||
| 	fi, ok := p.slowTags[t] | ||||
| 	return fi, ok | ||||
| } | ||||
| 
 | ||||
| func (p *tagMap) put(t int, fi int) { | ||||
| 	if t > 0 && t < tagMapFastLimit { | ||||
| 		for len(p.fastTags) < t+1 { | ||||
| 			p.fastTags = append(p.fastTags, -1) | ||||
| 		} | ||||
| 		p.fastTags[t] = fi | ||||
| 		return | ||||
| 	} | ||||
| 	if p.slowTags == nil { | ||||
| 		p.slowTags = make(map[int]int) | ||||
| 	} | ||||
| 	p.slowTags[t] = fi | ||||
| } | ||||
| 
 | ||||
| // StructProperties represents properties for all the fields of a struct.
 | ||||
| // decoderTags and decoderOrigNames should only be used by the decoder.
 | ||||
| type StructProperties struct { | ||||
| 	Prop             []*Properties  // properties for each field
 | ||||
| 	reqCount         int            // required count
 | ||||
| 	decoderTags      tagMap         // map from proto tag to struct field number
 | ||||
| 	decoderOrigNames map[string]int // map from original name to struct field number
 | ||||
| 	order            []int          // list of struct field numbers in tag order
 | ||||
| 	unrecField       field          // field id of the XXX_unrecognized []byte field
 | ||||
| 	extendable       bool           // is this an extendable proto
 | ||||
| 
 | ||||
| 	oneofMarshaler   oneofMarshaler | ||||
| 	oneofUnmarshaler oneofUnmarshaler | ||||
| 	oneofSizer       oneofSizer | ||||
| 	stype            reflect.Type | ||||
| 
 | ||||
| 	// OneofTypes contains information about the oneof fields in this message.
 | ||||
| 	// It is keyed by the original name of a field.
 | ||||
| 	OneofTypes map[string]*OneofProperties | ||||
| } | ||||
| 
 | ||||
| // OneofProperties represents information about a specific field in a oneof.
 | ||||
| type OneofProperties struct { | ||||
| 	Type  reflect.Type // pointer to generated struct type for this oneof field
 | ||||
| 	Field int          // struct field number of the containing oneof in the message
 | ||||
| 	Prop  *Properties | ||||
| } | ||||
| 
 | ||||
| // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
 | ||||
| // See encode.go, (*Buffer).enc_struct.
 | ||||
| 
 | ||||
| func (sp *StructProperties) Len() int { return len(sp.order) } | ||||
| func (sp *StructProperties) Less(i, j int) bool { | ||||
| 	return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag | ||||
| } | ||||
| func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } | ||||
| 
 | ||||
| // Properties represents the protocol-specific behavior of a single struct field.
 | ||||
| type Properties struct { | ||||
| 	Name     string // name of the field, for error messages
 | ||||
| 	OrigName string // original name before protocol compiler (always set)
 | ||||
| 	JSONName string // name to use for JSON; determined by protoc
 | ||||
| 	Wire     string | ||||
| 	WireType int | ||||
| 	Tag      int | ||||
| 	Required bool | ||||
| 	Optional bool | ||||
| 	Repeated bool | ||||
| 	Packed   bool   // relevant for repeated primitives only
 | ||||
| 	Enum     string // set for enum types only
 | ||||
| 	proto3   bool   // whether this is known to be a proto3 field; set for []byte only
 | ||||
| 	oneof    bool   // whether this is a oneof field
 | ||||
| 
 | ||||
| 	Default    string // default value
 | ||||
| 	HasDefault bool   // whether an explicit default was provided
 | ||||
| 	def_uint64 uint64 | ||||
| 
 | ||||
| 	enc           encoder | ||||
| 	valEnc        valueEncoder // set for bool and numeric types only
 | ||||
| 	field         field | ||||
| 	tagcode       []byte // encoding of EncodeVarint((Tag<<3)|WireType)
 | ||||
| 	tagbuf        [8]byte | ||||
| 	stype         reflect.Type      // set for struct types only
 | ||||
| 	sprop         *StructProperties // set for struct types only
 | ||||
| 	isMarshaler   bool | ||||
| 	isUnmarshaler bool | ||||
| 
 | ||||
| 	mtype    reflect.Type // set for map types only
 | ||||
| 	mkeyprop *Properties  // set for map types only
 | ||||
| 	mvalprop *Properties  // set for map types only
 | ||||
| 
 | ||||
| 	size    sizer | ||||
| 	valSize valueSizer // set for bool and numeric types only
 | ||||
| 
 | ||||
| 	dec    decoder | ||||
| 	valDec valueDecoder // set for bool and numeric types only
 | ||||
| 
 | ||||
| 	// If this is a packable field, this will be the decoder for the packed version of the field.
 | ||||
| 	packedDec decoder | ||||
| } | ||||
| 
 | ||||
| // String formats the properties in the protobuf struct field tag style.
 | ||||
| func (p *Properties) String() string { | ||||
| 	s := p.Wire | ||||
| 	s = "," | ||||
| 	s += strconv.Itoa(p.Tag) | ||||
| 	if p.Required { | ||||
| 		s += ",req" | ||||
| 	} | ||||
| 	if p.Optional { | ||||
| 		s += ",opt" | ||||
| 	} | ||||
| 	if p.Repeated { | ||||
| 		s += ",rep" | ||||
| 	} | ||||
| 	if p.Packed { | ||||
| 		s += ",packed" | ||||
| 	} | ||||
| 	s += ",name=" + p.OrigName | ||||
| 	if p.JSONName != p.OrigName { | ||||
| 		s += ",json=" + p.JSONName | ||||
| 	} | ||||
| 	if p.proto3 { | ||||
| 		s += ",proto3" | ||||
| 	} | ||||
| 	if p.oneof { | ||||
| 		s += ",oneof" | ||||
| 	} | ||||
| 	if len(p.Enum) > 0 { | ||||
| 		s += ",enum=" + p.Enum | ||||
| 	} | ||||
| 	if p.HasDefault { | ||||
| 		s += ",def=" + p.Default | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // Parse populates p by parsing a string in the protobuf struct field tag style.
 | ||||
| func (p *Properties) Parse(s string) { | ||||
| 	// "bytes,49,opt,name=foo,def=hello!"
 | ||||
| 	fields := strings.Split(s, ",") // breaks def=, but handled below.
 | ||||
| 	if len(fields) < 2 { | ||||
| 		fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	p.Wire = fields[0] | ||||
| 	switch p.Wire { | ||||
| 	case "varint": | ||||
| 		p.WireType = WireVarint | ||||
| 		p.valEnc = (*Buffer).EncodeVarint | ||||
| 		p.valDec = (*Buffer).DecodeVarint | ||||
| 		p.valSize = sizeVarint | ||||
| 	case "fixed32": | ||||
| 		p.WireType = WireFixed32 | ||||
| 		p.valEnc = (*Buffer).EncodeFixed32 | ||||
| 		p.valDec = (*Buffer).DecodeFixed32 | ||||
| 		p.valSize = sizeFixed32 | ||||
| 	case "fixed64": | ||||
| 		p.WireType = WireFixed64 | ||||
| 		p.valEnc = (*Buffer).EncodeFixed64 | ||||
| 		p.valDec = (*Buffer).DecodeFixed64 | ||||
| 		p.valSize = sizeFixed64 | ||||
| 	case "zigzag32": | ||||
| 		p.WireType = WireVarint | ||||
| 		p.valEnc = (*Buffer).EncodeZigzag32 | ||||
| 		p.valDec = (*Buffer).DecodeZigzag32 | ||||
| 		p.valSize = sizeZigzag32 | ||||
| 	case "zigzag64": | ||||
| 		p.WireType = WireVarint | ||||
| 		p.valEnc = (*Buffer).EncodeZigzag64 | ||||
| 		p.valDec = (*Buffer).DecodeZigzag64 | ||||
| 		p.valSize = sizeZigzag64 | ||||
| 	case "bytes", "group": | ||||
| 		p.WireType = WireBytes | ||||
| 		// no numeric converter for non-numeric types
 | ||||
| 	default: | ||||
| 		fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	p.Tag, err = strconv.Atoi(fields[1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	for i := 2; i < len(fields); i++ { | ||||
| 		f := fields[i] | ||||
| 		switch { | ||||
| 		case f == "req": | ||||
| 			p.Required = true | ||||
| 		case f == "opt": | ||||
| 			p.Optional = true | ||||
| 		case f == "rep": | ||||
| 			p.Repeated = true | ||||
| 		case f == "packed": | ||||
| 			p.Packed = true | ||||
| 		case strings.HasPrefix(f, "name="): | ||||
| 			p.OrigName = f[5:] | ||||
| 		case strings.HasPrefix(f, "json="): | ||||
| 			p.JSONName = f[5:] | ||||
| 		case strings.HasPrefix(f, "enum="): | ||||
| 			p.Enum = f[5:] | ||||
| 		case f == "proto3": | ||||
| 			p.proto3 = true | ||||
| 		case f == "oneof": | ||||
| 			p.oneof = true | ||||
| 		case strings.HasPrefix(f, "def="): | ||||
| 			p.HasDefault = true | ||||
| 			p.Default = f[4:] // rest of string
 | ||||
| 			if i+1 < len(fields) { | ||||
| 				// Commas aren't escaped, and def is always last.
 | ||||
| 				p.Default += "," + strings.Join(fields[i+1:], ",") | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func logNoSliceEnc(t1, t2 reflect.Type) { | ||||
| 	fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) | ||||
| } | ||||
| 
 | ||||
| var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() | ||||
| 
 | ||||
| // Initialize the fields for encoding and decoding.
 | ||||
| func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { | ||||
| 	p.enc = nil | ||||
| 	p.dec = nil | ||||
| 	p.size = nil | ||||
| 
 | ||||
| 	switch t1 := typ; t1.Kind() { | ||||
| 	default: | ||||
| 		fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) | ||||
| 
 | ||||
| 	// proto3 scalar types
 | ||||
| 
 | ||||
| 	case reflect.Bool: | ||||
| 		p.enc = (*Buffer).enc_proto3_bool | ||||
| 		p.dec = (*Buffer).dec_proto3_bool | ||||
| 		p.size = size_proto3_bool | ||||
| 	case reflect.Int32: | ||||
| 		p.enc = (*Buffer).enc_proto3_int32 | ||||
| 		p.dec = (*Buffer).dec_proto3_int32 | ||||
| 		p.size = size_proto3_int32 | ||||
| 	case reflect.Uint32: | ||||
| 		p.enc = (*Buffer).enc_proto3_uint32 | ||||
| 		p.dec = (*Buffer).dec_proto3_int32 // can reuse
 | ||||
| 		p.size = size_proto3_uint32 | ||||
| 	case reflect.Int64, reflect.Uint64: | ||||
| 		p.enc = (*Buffer).enc_proto3_int64 | ||||
| 		p.dec = (*Buffer).dec_proto3_int64 | ||||
| 		p.size = size_proto3_int64 | ||||
| 	case reflect.Float32: | ||||
| 		p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
 | ||||
| 		p.dec = (*Buffer).dec_proto3_int32 | ||||
| 		p.size = size_proto3_uint32 | ||||
| 	case reflect.Float64: | ||||
| 		p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
 | ||||
| 		p.dec = (*Buffer).dec_proto3_int64 | ||||
| 		p.size = size_proto3_int64 | ||||
| 	case reflect.String: | ||||
| 		p.enc = (*Buffer).enc_proto3_string | ||||
| 		p.dec = (*Buffer).dec_proto3_string | ||||
| 		p.size = size_proto3_string | ||||
| 
 | ||||
| 	case reflect.Ptr: | ||||
| 		switch t2 := t1.Elem(); t2.Kind() { | ||||
| 		default: | ||||
| 			fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) | ||||
| 			break | ||||
| 		case reflect.Bool: | ||||
| 			p.enc = (*Buffer).enc_bool | ||||
| 			p.dec = (*Buffer).dec_bool | ||||
| 			p.size = size_bool | ||||
| 		case reflect.Int32: | ||||
| 			p.enc = (*Buffer).enc_int32 | ||||
| 			p.dec = (*Buffer).dec_int32 | ||||
| 			p.size = size_int32 | ||||
| 		case reflect.Uint32: | ||||
| 			p.enc = (*Buffer).enc_uint32 | ||||
| 			p.dec = (*Buffer).dec_int32 // can reuse
 | ||||
| 			p.size = size_uint32 | ||||
| 		case reflect.Int64, reflect.Uint64: | ||||
| 			p.enc = (*Buffer).enc_int64 | ||||
| 			p.dec = (*Buffer).dec_int64 | ||||
| 			p.size = size_int64 | ||||
| 		case reflect.Float32: | ||||
| 			p.enc = (*Buffer).enc_uint32 // can just treat them as bits
 | ||||
| 			p.dec = (*Buffer).dec_int32 | ||||
| 			p.size = size_uint32 | ||||
| 		case reflect.Float64: | ||||
| 			p.enc = (*Buffer).enc_int64 // can just treat them as bits
 | ||||
| 			p.dec = (*Buffer).dec_int64 | ||||
| 			p.size = size_int64 | ||||
| 		case reflect.String: | ||||
| 			p.enc = (*Buffer).enc_string | ||||
| 			p.dec = (*Buffer).dec_string | ||||
| 			p.size = size_string | ||||
| 		case reflect.Struct: | ||||
| 			p.stype = t1.Elem() | ||||
| 			p.isMarshaler = isMarshaler(t1) | ||||
| 			p.isUnmarshaler = isUnmarshaler(t1) | ||||
| 			if p.Wire == "bytes" { | ||||
| 				p.enc = (*Buffer).enc_struct_message | ||||
| 				p.dec = (*Buffer).dec_struct_message | ||||
| 				p.size = size_struct_message | ||||
| 			} else { | ||||
| 				p.enc = (*Buffer).enc_struct_group | ||||
| 				p.dec = (*Buffer).dec_struct_group | ||||
| 				p.size = size_struct_group | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Slice: | ||||
| 		switch t2 := t1.Elem(); t2.Kind() { | ||||
| 		default: | ||||
| 			logNoSliceEnc(t1, t2) | ||||
| 			break | ||||
| 		case reflect.Bool: | ||||
| 			if p.Packed { | ||||
| 				p.enc = (*Buffer).enc_slice_packed_bool | ||||
| 				p.size = size_slice_packed_bool | ||||
| 			} else { | ||||
| 				p.enc = (*Buffer).enc_slice_bool | ||||
| 				p.size = size_slice_bool | ||||
| 			} | ||||
| 			p.dec = (*Buffer).dec_slice_bool | ||||
| 			p.packedDec = (*Buffer).dec_slice_packed_bool | ||||
| 		case reflect.Int32: | ||||
| 			if p.Packed { | ||||
| 				p.enc = (*Buffer).enc_slice_packed_int32 | ||||
| 				p.size = size_slice_packed_int32 | ||||
| 			} else { | ||||
| 				p.enc = (*Buffer).enc_slice_int32 | ||||
| 				p.size = size_slice_int32 | ||||
| 			} | ||||
| 			p.dec = (*Buffer).dec_slice_int32 | ||||
| 			p.packedDec = (*Buffer).dec_slice_packed_int32 | ||||
| 		case reflect.Uint32: | ||||
| 			if p.Packed { | ||||
| 				p.enc = (*Buffer).enc_slice_packed_uint32 | ||||
| 				p.size = size_slice_packed_uint32 | ||||
| 			} else { | ||||
| 				p.enc = (*Buffer).enc_slice_uint32 | ||||
| 				p.size = size_slice_uint32 | ||||
| 			} | ||||
| 			p.dec = (*Buffer).dec_slice_int32 | ||||
| 			p.packedDec = (*Buffer).dec_slice_packed_int32 | ||||
| 		case reflect.Int64, reflect.Uint64: | ||||
| 			if p.Packed { | ||||
| 				p.enc = (*Buffer).enc_slice_packed_int64 | ||||
| 				p.size = size_slice_packed_int64 | ||||
| 			} else { | ||||
| 				p.enc = (*Buffer).enc_slice_int64 | ||||
| 				p.size = size_slice_int64 | ||||
| 			} | ||||
| 			p.dec = (*Buffer).dec_slice_int64 | ||||
| 			p.packedDec = (*Buffer).dec_slice_packed_int64 | ||||
| 		case reflect.Uint8: | ||||
| 			p.dec = (*Buffer).dec_slice_byte | ||||
| 			if p.proto3 { | ||||
| 				p.enc = (*Buffer).enc_proto3_slice_byte | ||||
| 				p.size = size_proto3_slice_byte | ||||
| 			} else { | ||||
| 				p.enc = (*Buffer).enc_slice_byte | ||||
| 				p.size = size_slice_byte | ||||
| 			} | ||||
| 		case reflect.Float32, reflect.Float64: | ||||
| 			switch t2.Bits() { | ||||
| 			case 32: | ||||
| 				// can just treat them as bits
 | ||||
| 				if p.Packed { | ||||
| 					p.enc = (*Buffer).enc_slice_packed_uint32 | ||||
| 					p.size = size_slice_packed_uint32 | ||||
| 				} else { | ||||
| 					p.enc = (*Buffer).enc_slice_uint32 | ||||
| 					p.size = size_slice_uint32 | ||||
| 				} | ||||
| 				p.dec = (*Buffer).dec_slice_int32 | ||||
| 				p.packedDec = (*Buffer).dec_slice_packed_int32 | ||||
| 			case 64: | ||||
| 				// can just treat them as bits
 | ||||
| 				if p.Packed { | ||||
| 					p.enc = (*Buffer).enc_slice_packed_int64 | ||||
| 					p.size = size_slice_packed_int64 | ||||
| 				} else { | ||||
| 					p.enc = (*Buffer).enc_slice_int64 | ||||
| 					p.size = size_slice_int64 | ||||
| 				} | ||||
| 				p.dec = (*Buffer).dec_slice_int64 | ||||
| 				p.packedDec = (*Buffer).dec_slice_packed_int64 | ||||
| 			default: | ||||
| 				logNoSliceEnc(t1, t2) | ||||
| 				break | ||||
| 			} | ||||
| 		case reflect.String: | ||||
| 			p.enc = (*Buffer).enc_slice_string | ||||
| 			p.dec = (*Buffer).dec_slice_string | ||||
| 			p.size = size_slice_string | ||||
| 		case reflect.Ptr: | ||||
| 			switch t3 := t2.Elem(); t3.Kind() { | ||||
| 			default: | ||||
| 				fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) | ||||
| 				break | ||||
| 			case reflect.Struct: | ||||
| 				p.stype = t2.Elem() | ||||
| 				p.isMarshaler = isMarshaler(t2) | ||||
| 				p.isUnmarshaler = isUnmarshaler(t2) | ||||
| 				if p.Wire == "bytes" { | ||||
| 					p.enc = (*Buffer).enc_slice_struct_message | ||||
| 					p.dec = (*Buffer).dec_slice_struct_message | ||||
| 					p.size = size_slice_struct_message | ||||
| 				} else { | ||||
| 					p.enc = (*Buffer).enc_slice_struct_group | ||||
| 					p.dec = (*Buffer).dec_slice_struct_group | ||||
| 					p.size = size_slice_struct_group | ||||
| 				} | ||||
| 			} | ||||
| 		case reflect.Slice: | ||||
| 			switch t2.Elem().Kind() { | ||||
| 			default: | ||||
| 				fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) | ||||
| 				break | ||||
| 			case reflect.Uint8: | ||||
| 				p.enc = (*Buffer).enc_slice_slice_byte | ||||
| 				p.dec = (*Buffer).dec_slice_slice_byte | ||||
| 				p.size = size_slice_slice_byte | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Map: | ||||
| 		p.enc = (*Buffer).enc_new_map | ||||
| 		p.dec = (*Buffer).dec_new_map | ||||
| 		p.size = size_new_map | ||||
| 
 | ||||
| 		p.mtype = t1 | ||||
| 		p.mkeyprop = &Properties{} | ||||
| 		p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) | ||||
| 		p.mvalprop = &Properties{} | ||||
| 		vtype := p.mtype.Elem() | ||||
| 		if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { | ||||
| 			// The value type is not a message (*T) or bytes ([]byte),
 | ||||
| 			// so we need encoders for the pointer to this type.
 | ||||
| 			vtype = reflect.PtrTo(vtype) | ||||
| 		} | ||||
| 		p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) | ||||
| 	} | ||||
| 
 | ||||
| 	// precalculate tag code
 | ||||
| 	wire := p.WireType | ||||
| 	if p.Packed { | ||||
| 		wire = WireBytes | ||||
| 	} | ||||
| 	x := uint32(p.Tag)<<3 | uint32(wire) | ||||
| 	i := 0 | ||||
| 	for i = 0; x > 127; i++ { | ||||
| 		p.tagbuf[i] = 0x80 | uint8(x&0x7F) | ||||
| 		x >>= 7 | ||||
| 	} | ||||
| 	p.tagbuf[i] = uint8(x) | ||||
| 	p.tagcode = p.tagbuf[0 : i+1] | ||||
| 
 | ||||
| 	if p.stype != nil { | ||||
| 		if lockGetProp { | ||||
| 			p.sprop = GetProperties(p.stype) | ||||
| 		} else { | ||||
| 			p.sprop = getPropertiesLocked(p.stype) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	marshalerType   = reflect.TypeOf((*Marshaler)(nil)).Elem() | ||||
| 	unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() | ||||
| ) | ||||
| 
 | ||||
| // isMarshaler reports whether type t implements Marshaler.
 | ||||
| func isMarshaler(t reflect.Type) bool { | ||||
| 	// We're checking for (likely) pointer-receiver methods
 | ||||
| 	// so if t is not a pointer, something is very wrong.
 | ||||
| 	// The calls above only invoke isMarshaler on pointer types.
 | ||||
| 	if t.Kind() != reflect.Ptr { | ||||
| 		panic("proto: misuse of isMarshaler") | ||||
| 	} | ||||
| 	return t.Implements(marshalerType) | ||||
| } | ||||
| 
 | ||||
| // isUnmarshaler reports whether type t implements Unmarshaler.
 | ||||
| func isUnmarshaler(t reflect.Type) bool { | ||||
| 	// We're checking for (likely) pointer-receiver methods
 | ||||
| 	// so if t is not a pointer, something is very wrong.
 | ||||
| 	// The calls above only invoke isUnmarshaler on pointer types.
 | ||||
| 	if t.Kind() != reflect.Ptr { | ||||
| 		panic("proto: misuse of isUnmarshaler") | ||||
| 	} | ||||
| 	return t.Implements(unmarshalerType) | ||||
| } | ||||
| 
 | ||||
| // Init populates the properties from a protocol buffer struct tag.
 | ||||
| func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { | ||||
| 	p.init(typ, name, tag, f, true) | ||||
| } | ||||
| 
 | ||||
| func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { | ||||
| 	// "bytes,49,opt,def=hello!"
 | ||||
| 	p.Name = name | ||||
| 	p.OrigName = name | ||||
| 	if f != nil { | ||||
| 		p.field = toField(f) | ||||
| 	} | ||||
| 	if tag == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	p.Parse(tag) | ||||
| 	p.setEncAndDec(typ, f, lockGetProp) | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	propertiesMu  sync.RWMutex | ||||
| 	propertiesMap = make(map[reflect.Type]*StructProperties) | ||||
| ) | ||||
| 
 | ||||
| // GetProperties returns the list of properties for the type represented by t.
 | ||||
| // t must represent a generated struct type of a protocol message.
 | ||||
| func GetProperties(t reflect.Type) *StructProperties { | ||||
| 	if t.Kind() != reflect.Struct { | ||||
| 		panic("proto: type must have kind struct") | ||||
| 	} | ||||
| 
 | ||||
| 	// Most calls to GetProperties in a long-running program will be
 | ||||
| 	// retrieving details for types we have seen before.
 | ||||
| 	propertiesMu.RLock() | ||||
| 	sprop, ok := propertiesMap[t] | ||||
| 	propertiesMu.RUnlock() | ||||
| 	if ok { | ||||
| 		if collectStats { | ||||
| 			stats.Chit++ | ||||
| 		} | ||||
| 		return sprop | ||||
| 	} | ||||
| 
 | ||||
| 	propertiesMu.Lock() | ||||
| 	sprop = getPropertiesLocked(t) | ||||
| 	propertiesMu.Unlock() | ||||
| 	return sprop | ||||
| } | ||||
| 
 | ||||
| // getPropertiesLocked requires that propertiesMu is held.
 | ||||
| func getPropertiesLocked(t reflect.Type) *StructProperties { | ||||
| 	if prop, ok := propertiesMap[t]; ok { | ||||
| 		if collectStats { | ||||
| 			stats.Chit++ | ||||
| 		} | ||||
| 		return prop | ||||
| 	} | ||||
| 	if collectStats { | ||||
| 		stats.Cmiss++ | ||||
| 	} | ||||
| 
 | ||||
| 	prop := new(StructProperties) | ||||
| 	// in case of recursive protos, fill this in now.
 | ||||
| 	propertiesMap[t] = prop | ||||
| 
 | ||||
| 	// build properties
 | ||||
| 	prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || | ||||
| 		reflect.PtrTo(t).Implements(extendableProtoV1Type) | ||||
| 	prop.unrecField = invalidField | ||||
| 	prop.Prop = make([]*Properties, t.NumField()) | ||||
| 	prop.order = make([]int, t.NumField()) | ||||
| 
 | ||||
| 	for i := 0; i < t.NumField(); i++ { | ||||
| 		f := t.Field(i) | ||||
| 		p := new(Properties) | ||||
| 		name := f.Name | ||||
| 		p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) | ||||
| 
 | ||||
| 		if f.Name == "XXX_InternalExtensions" { // special case
 | ||||
| 			p.enc = (*Buffer).enc_exts | ||||
| 			p.dec = nil // not needed
 | ||||
| 			p.size = size_exts | ||||
| 		} else if f.Name == "XXX_extensions" { // special case
 | ||||
| 			p.enc = (*Buffer).enc_map | ||||
| 			p.dec = nil // not needed
 | ||||
| 			p.size = size_map | ||||
| 		} else if f.Name == "XXX_unrecognized" { // special case
 | ||||
| 			prop.unrecField = toField(&f) | ||||
| 		} | ||||
| 		oneof := f.Tag.Get("protobuf_oneof") // special case
 | ||||
| 		if oneof != "" { | ||||
| 			// Oneof fields don't use the traditional protobuf tag.
 | ||||
| 			p.OrigName = oneof | ||||
| 		} | ||||
| 		prop.Prop[i] = p | ||||
| 		prop.order[i] = i | ||||
| 		if debug { | ||||
| 			print(i, " ", f.Name, " ", t.String(), " ") | ||||
| 			if p.Tag > 0 { | ||||
| 				print(p.String()) | ||||
| 			} | ||||
| 			print("\n") | ||||
| 		} | ||||
| 		if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { | ||||
| 			fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Re-order prop.order.
 | ||||
| 	sort.Sort(prop) | ||||
| 
 | ||||
| 	type oneofMessage interface { | ||||
| 		XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) | ||||
| 	} | ||||
| 	if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { | ||||
| 		var oots []interface{} | ||||
| 		prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() | ||||
| 		prop.stype = t | ||||
| 
 | ||||
| 		// Interpret oneof metadata.
 | ||||
| 		prop.OneofTypes = make(map[string]*OneofProperties) | ||||
| 		for _, oot := range oots { | ||||
| 			oop := &OneofProperties{ | ||||
| 				Type: reflect.ValueOf(oot).Type(), // *T
 | ||||
| 				Prop: new(Properties), | ||||
| 			} | ||||
| 			sft := oop.Type.Elem().Field(0) | ||||
| 			oop.Prop.Name = sft.Name | ||||
| 			oop.Prop.Parse(sft.Tag.Get("protobuf")) | ||||
| 			// There will be exactly one interface field that
 | ||||
| 			// this new value is assignable to.
 | ||||
| 			for i := 0; i < t.NumField(); i++ { | ||||
| 				f := t.Field(i) | ||||
| 				if f.Type.Kind() != reflect.Interface { | ||||
| 					continue | ||||
| 				} | ||||
| 				if !oop.Type.AssignableTo(f.Type) { | ||||
| 					continue | ||||
| 				} | ||||
| 				oop.Field = i | ||||
| 				break | ||||
| 			} | ||||
| 			prop.OneofTypes[oop.Prop.OrigName] = oop | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// build required counts
 | ||||
| 	// build tags
 | ||||
| 	reqCount := 0 | ||||
| 	prop.decoderOrigNames = make(map[string]int) | ||||
| 	for i, p := range prop.Prop { | ||||
| 		if strings.HasPrefix(p.Name, "XXX_") { | ||||
| 			// Internal fields should not appear in tags/origNames maps.
 | ||||
| 			// They are handled specially when encoding and decoding.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if p.Required { | ||||
| 			reqCount++ | ||||
| 		} | ||||
| 		prop.decoderTags.put(p.Tag, i) | ||||
| 		prop.decoderOrigNames[p.OrigName] = i | ||||
| 	} | ||||
| 	prop.reqCount = reqCount | ||||
| 
 | ||||
| 	return prop | ||||
| } | ||||
| 
 | ||||
| // Return the Properties object for the x[0]'th field of the structure.
 | ||||
| func propByIndex(t reflect.Type, x []int) *Properties { | ||||
| 	if len(x) != 1 { | ||||
| 		fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) | ||||
| 		return nil | ||||
| 	} | ||||
| 	prop := GetProperties(t) | ||||
| 	return prop.Prop[x[0]] | ||||
| } | ||||
| 
 | ||||
| // Get the address and type of a pointer to a struct from an interface.
 | ||||
| func getbase(pb Message) (t reflect.Type, b structPointer, err error) { | ||||
| 	if pb == nil { | ||||
| 		err = ErrNil | ||||
| 		return | ||||
| 	} | ||||
| 	// get the reflect type of the pointer to the struct.
 | ||||
| 	t = reflect.TypeOf(pb) | ||||
| 	// get the address of the struct.
 | ||||
| 	value := reflect.ValueOf(pb) | ||||
| 	b = toStructPointer(value) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // A global registry of enum types.
 | ||||
| // The generated code will register the generated maps by calling RegisterEnum.
 | ||||
| 
 | ||||
| var enumValueMaps = make(map[string]map[string]int32) | ||||
| 
 | ||||
| // RegisterEnum is called from the generated code to install the enum descriptor
 | ||||
| // maps into the global table to aid parsing text format protocol buffers.
 | ||||
| func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { | ||||
| 	if _, ok := enumValueMaps[typeName]; ok { | ||||
| 		panic("proto: duplicate enum registered: " + typeName) | ||||
| 	} | ||||
| 	enumValueMaps[typeName] = valueMap | ||||
| } | ||||
| 
 | ||||
| // EnumValueMap returns the mapping from names to integers of the
 | ||||
| // enum type enumType, or a nil if not found.
 | ||||
| func EnumValueMap(enumType string) map[string]int32 { | ||||
| 	return enumValueMaps[enumType] | ||||
| } | ||||
| 
 | ||||
| // A registry of all linked message types.
 | ||||
| // The string is a fully-qualified proto name ("pkg.Message").
 | ||||
| var ( | ||||
| 	protoTypes    = make(map[string]reflect.Type) | ||||
| 	revProtoTypes = make(map[reflect.Type]string) | ||||
| ) | ||||
| 
 | ||||
| // RegisterType is called from generated code and maps from the fully qualified
 | ||||
| // proto name to the type (pointer to struct) of the protocol buffer.
 | ||||
| func RegisterType(x Message, name string) { | ||||
| 	if _, ok := protoTypes[name]; ok { | ||||
| 		// TODO: Some day, make this a panic.
 | ||||
| 		log.Printf("proto: duplicate proto type registered: %s", name) | ||||
| 		return | ||||
| 	} | ||||
| 	t := reflect.TypeOf(x) | ||||
| 	protoTypes[name] = t | ||||
| 	revProtoTypes[t] = name | ||||
| } | ||||
| 
 | ||||
| // MessageName returns the fully-qualified proto name for the given message type.
 | ||||
| func MessageName(x Message) string { | ||||
| 	type xname interface { | ||||
| 		XXX_MessageName() string | ||||
| 	} | ||||
| 	if m, ok := x.(xname); ok { | ||||
| 		return m.XXX_MessageName() | ||||
| 	} | ||||
| 	return revProtoTypes[reflect.TypeOf(x)] | ||||
| } | ||||
| 
 | ||||
| // MessageType returns the message type (pointer to struct) for a named message.
 | ||||
| func MessageType(name string) reflect.Type { return protoTypes[name] } | ||||
| 
 | ||||
| // A registry of all linked proto files.
 | ||||
| var ( | ||||
| 	protoFiles = make(map[string][]byte) // file name => fileDescriptor
 | ||||
| ) | ||||
| 
 | ||||
| // RegisterFile is called from generated code and maps from the
 | ||||
| // full file name of a .proto file to its compressed FileDescriptorProto.
 | ||||
| func RegisterFile(filename string, fileDescriptor []byte) { | ||||
| 	protoFiles[filename] = fileDescriptor | ||||
| } | ||||
| 
 | ||||
| // FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
 | ||||
| func FileDescriptor(filename string) []byte { return protoFiles[filename] } | ||||
|  | @ -0,0 +1,854 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| // Functions for writing the text protocol buffer format.
 | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"encoding" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	newline         = []byte("\n") | ||||
| 	spaces          = []byte("                                        ") | ||||
| 	gtNewline       = []byte(">\n") | ||||
| 	endBraceNewline = []byte("}\n") | ||||
| 	backslashN      = []byte{'\\', 'n'} | ||||
| 	backslashR      = []byte{'\\', 'r'} | ||||
| 	backslashT      = []byte{'\\', 't'} | ||||
| 	backslashDQ     = []byte{'\\', '"'} | ||||
| 	backslashBS     = []byte{'\\', '\\'} | ||||
| 	posInf          = []byte("inf") | ||||
| 	negInf          = []byte("-inf") | ||||
| 	nan             = []byte("nan") | ||||
| ) | ||||
| 
 | ||||
| type writer interface { | ||||
| 	io.Writer | ||||
| 	WriteByte(byte) error | ||||
| } | ||||
| 
 | ||||
| // textWriter is an io.Writer that tracks its indentation level.
 | ||||
| type textWriter struct { | ||||
| 	ind      int | ||||
| 	complete bool // if the current position is a complete line
 | ||||
| 	compact  bool // whether to write out as a one-liner
 | ||||
| 	w        writer | ||||
| } | ||||
| 
 | ||||
| func (w *textWriter) WriteString(s string) (n int, err error) { | ||||
| 	if !strings.Contains(s, "\n") { | ||||
| 		if !w.compact && w.complete { | ||||
| 			w.writeIndent() | ||||
| 		} | ||||
| 		w.complete = false | ||||
| 		return io.WriteString(w.w, s) | ||||
| 	} | ||||
| 	// WriteString is typically called without newlines, so this
 | ||||
| 	// codepath and its copy are rare.  We copy to avoid
 | ||||
| 	// duplicating all of Write's logic here.
 | ||||
| 	return w.Write([]byte(s)) | ||||
| } | ||||
| 
 | ||||
| func (w *textWriter) Write(p []byte) (n int, err error) { | ||||
| 	newlines := bytes.Count(p, newline) | ||||
| 	if newlines == 0 { | ||||
| 		if !w.compact && w.complete { | ||||
| 			w.writeIndent() | ||||
| 		} | ||||
| 		n, err = w.w.Write(p) | ||||
| 		w.complete = false | ||||
| 		return n, err | ||||
| 	} | ||||
| 
 | ||||
| 	frags := bytes.SplitN(p, newline, newlines+1) | ||||
| 	if w.compact { | ||||
| 		for i, frag := range frags { | ||||
| 			if i > 0 { | ||||
| 				if err := w.w.WriteByte(' '); err != nil { | ||||
| 					return n, err | ||||
| 				} | ||||
| 				n++ | ||||
| 			} | ||||
| 			nn, err := w.w.Write(frag) | ||||
| 			n += nn | ||||
| 			if err != nil { | ||||
| 				return n, err | ||||
| 			} | ||||
| 		} | ||||
| 		return n, nil | ||||
| 	} | ||||
| 
 | ||||
| 	for i, frag := range frags { | ||||
| 		if w.complete { | ||||
| 			w.writeIndent() | ||||
| 		} | ||||
| 		nn, err := w.w.Write(frag) | ||||
| 		n += nn | ||||
| 		if err != nil { | ||||
| 			return n, err | ||||
| 		} | ||||
| 		if i+1 < len(frags) { | ||||
| 			if err := w.w.WriteByte('\n'); err != nil { | ||||
| 				return n, err | ||||
| 			} | ||||
| 			n++ | ||||
| 		} | ||||
| 	} | ||||
| 	w.complete = len(frags[len(frags)-1]) == 0 | ||||
| 	return n, nil | ||||
| } | ||||
| 
 | ||||
| func (w *textWriter) WriteByte(c byte) error { | ||||
| 	if w.compact && c == '\n' { | ||||
| 		c = ' ' | ||||
| 	} | ||||
| 	if !w.compact && w.complete { | ||||
| 		w.writeIndent() | ||||
| 	} | ||||
| 	err := w.w.WriteByte(c) | ||||
| 	w.complete = c == '\n' | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (w *textWriter) indent() { w.ind++ } | ||||
| 
 | ||||
| func (w *textWriter) unindent() { | ||||
| 	if w.ind == 0 { | ||||
| 		log.Print("proto: textWriter unindented too far") | ||||
| 		return | ||||
| 	} | ||||
| 	w.ind-- | ||||
| } | ||||
| 
 | ||||
| func writeName(w *textWriter, props *Properties) error { | ||||
| 	if _, err := w.WriteString(props.OrigName); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if props.Wire != "group" { | ||||
| 		return w.WriteByte(':') | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // raw is the interface satisfied by RawMessage.
 | ||||
| type raw interface { | ||||
| 	Bytes() []byte | ||||
| } | ||||
| 
 | ||||
| func requiresQuotes(u string) bool { | ||||
| 	// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
 | ||||
| 	for _, ch := range u { | ||||
| 		switch { | ||||
| 		case ch == '.' || ch == '/' || ch == '_': | ||||
| 			continue | ||||
| 		case '0' <= ch && ch <= '9': | ||||
| 			continue | ||||
| 		case 'A' <= ch && ch <= 'Z': | ||||
| 			continue | ||||
| 		case 'a' <= ch && ch <= 'z': | ||||
| 			continue | ||||
| 		default: | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // isAny reports whether sv is a google.protobuf.Any message
 | ||||
| func isAny(sv reflect.Value) bool { | ||||
| 	type wkt interface { | ||||
| 		XXX_WellKnownType() string | ||||
| 	} | ||||
| 	t, ok := sv.Addr().Interface().(wkt) | ||||
| 	return ok && t.XXX_WellKnownType() == "Any" | ||||
| } | ||||
| 
 | ||||
| // writeProto3Any writes an expanded google.protobuf.Any message.
 | ||||
| //
 | ||||
| // It returns (false, nil) if sv value can't be unmarshaled (e.g. because
 | ||||
| // required messages are not linked in).
 | ||||
| //
 | ||||
| // It returns (true, error) when sv was written in expanded format or an error
 | ||||
| // was encountered.
 | ||||
| func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { | ||||
| 	turl := sv.FieldByName("TypeUrl") | ||||
| 	val := sv.FieldByName("Value") | ||||
| 	if !turl.IsValid() || !val.IsValid() { | ||||
| 		return true, errors.New("proto: invalid google.protobuf.Any message") | ||||
| 	} | ||||
| 
 | ||||
| 	b, ok := val.Interface().([]byte) | ||||
| 	if !ok { | ||||
| 		return true, errors.New("proto: invalid google.protobuf.Any message") | ||||
| 	} | ||||
| 
 | ||||
| 	parts := strings.Split(turl.String(), "/") | ||||
| 	mt := MessageType(parts[len(parts)-1]) | ||||
| 	if mt == nil { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 	m := reflect.New(mt.Elem()) | ||||
| 	if err := Unmarshal(b, m.Interface().(Message)); err != nil { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 	w.Write([]byte("[")) | ||||
| 	u := turl.String() | ||||
| 	if requiresQuotes(u) { | ||||
| 		writeString(w, u) | ||||
| 	} else { | ||||
| 		w.Write([]byte(u)) | ||||
| 	} | ||||
| 	if w.compact { | ||||
| 		w.Write([]byte("]:<")) | ||||
| 	} else { | ||||
| 		w.Write([]byte("]: <\n")) | ||||
| 		w.ind++ | ||||
| 	} | ||||
| 	if err := tm.writeStruct(w, m.Elem()); err != nil { | ||||
| 		return true, err | ||||
| 	} | ||||
| 	if w.compact { | ||||
| 		w.Write([]byte("> ")) | ||||
| 	} else { | ||||
| 		w.ind-- | ||||
| 		w.Write([]byte(">\n")) | ||||
| 	} | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { | ||||
| 	if tm.ExpandAny && isAny(sv) { | ||||
| 		if canExpand, err := tm.writeProto3Any(w, sv); canExpand { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	st := sv.Type() | ||||
| 	sprops := GetProperties(st) | ||||
| 	for i := 0; i < sv.NumField(); i++ { | ||||
| 		fv := sv.Field(i) | ||||
| 		props := sprops.Prop[i] | ||||
| 		name := st.Field(i).Name | ||||
| 
 | ||||
| 		if strings.HasPrefix(name, "XXX_") { | ||||
| 			// There are two XXX_ fields:
 | ||||
| 			//   XXX_unrecognized []byte
 | ||||
| 			//   XXX_extensions   map[int32]proto.Extension
 | ||||
| 			// The first is handled here;
 | ||||
| 			// the second is handled at the bottom of this function.
 | ||||
| 			if name == "XXX_unrecognized" && !fv.IsNil() { | ||||
| 				if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if fv.Kind() == reflect.Ptr && fv.IsNil() { | ||||
| 			// Field not filled in. This could be an optional field or
 | ||||
| 			// a required field that wasn't filled in. Either way, there
 | ||||
| 			// isn't anything we can show for it.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if fv.Kind() == reflect.Slice && fv.IsNil() { | ||||
| 			// Repeated field that is empty, or a bytes field that is unused.
 | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if props.Repeated && fv.Kind() == reflect.Slice { | ||||
| 			// Repeated field.
 | ||||
| 			for j := 0; j < fv.Len(); j++ { | ||||
| 				if err := writeName(w, props); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if !w.compact { | ||||
| 					if err := w.WriteByte(' '); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				v := fv.Index(j) | ||||
| 				if v.Kind() == reflect.Ptr && v.IsNil() { | ||||
| 					// A nil message in a repeated field is not valid,
 | ||||
| 					// but we can handle that more gracefully than panicking.
 | ||||
| 					if _, err := w.Write([]byte("<nil>\n")); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 				if err := tm.writeAny(w, v, props); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if err := w.WriteByte('\n'); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if fv.Kind() == reflect.Map { | ||||
| 			// Map fields are rendered as a repeated struct with key/value fields.
 | ||||
| 			keys := fv.MapKeys() | ||||
| 			sort.Sort(mapKeys(keys)) | ||||
| 			for _, key := range keys { | ||||
| 				val := fv.MapIndex(key) | ||||
| 				if err := writeName(w, props); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if !w.compact { | ||||
| 					if err := w.WriteByte(' '); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				// open struct
 | ||||
| 				if err := w.WriteByte('<'); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if !w.compact { | ||||
| 					if err := w.WriteByte('\n'); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				w.indent() | ||||
| 				// key
 | ||||
| 				if _, err := w.WriteString("key:"); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if !w.compact { | ||||
| 					if err := w.WriteByte(' '); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				if err := tm.writeAny(w, key, props.mkeyprop); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if err := w.WriteByte('\n'); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				// nil values aren't legal, but we can avoid panicking because of them.
 | ||||
| 				if val.Kind() != reflect.Ptr || !val.IsNil() { | ||||
| 					// value
 | ||||
| 					if _, err := w.WriteString("value:"); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if !w.compact { | ||||
| 						if err := w.WriteByte(' '); err != nil { | ||||
| 							return err | ||||
| 						} | ||||
| 					} | ||||
| 					if err := tm.writeAny(w, val, props.mvalprop); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if err := w.WriteByte('\n'); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				// close struct
 | ||||
| 				w.unindent() | ||||
| 				if err := w.WriteByte('>'); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if err := w.WriteByte('\n'); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { | ||||
| 			// empty bytes field
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { | ||||
| 			// proto3 non-repeated scalar field; skip if zero value
 | ||||
| 			if isProto3Zero(fv) { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if fv.Kind() == reflect.Interface { | ||||
| 			// Check if it is a oneof.
 | ||||
| 			if st.Field(i).Tag.Get("protobuf_oneof") != "" { | ||||
| 				// fv is nil, or holds a pointer to generated struct.
 | ||||
| 				// That generated struct has exactly one field,
 | ||||
| 				// which has a protobuf struct tag.
 | ||||
| 				if fv.IsNil() { | ||||
| 					continue | ||||
| 				} | ||||
| 				inner := fv.Elem().Elem() // interface -> *T -> T
 | ||||
| 				tag := inner.Type().Field(0).Tag.Get("protobuf") | ||||
| 				props = new(Properties) // Overwrite the outer props var, but not its pointee.
 | ||||
| 				props.Parse(tag) | ||||
| 				// Write the value in the oneof, not the oneof itself.
 | ||||
| 				fv = inner.Field(0) | ||||
| 
 | ||||
| 				// Special case to cope with malformed messages gracefully:
 | ||||
| 				// If the value in the oneof is a nil pointer, don't panic
 | ||||
| 				// in writeAny.
 | ||||
| 				if fv.Kind() == reflect.Ptr && fv.IsNil() { | ||||
| 					// Use errors.New so writeAny won't render quotes.
 | ||||
| 					msg := errors.New("/* nil */") | ||||
| 					fv = reflect.ValueOf(&msg).Elem() | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if err := writeName(w, props); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if !w.compact { | ||||
| 			if err := w.WriteByte(' '); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		if b, ok := fv.Interface().(raw); ok { | ||||
| 			if err := writeRaw(w, b.Bytes()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Enums have a String method, so writeAny will work fine.
 | ||||
| 		if err := tm.writeAny(w, fv, props); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if err := w.WriteByte('\n'); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Extensions (the XXX_extensions field).
 | ||||
| 	pv := sv.Addr() | ||||
| 	if _, ok := extendable(pv.Interface()); ok { | ||||
| 		if err := tm.writeExtensions(w, pv); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // writeRaw writes an uninterpreted raw message.
 | ||||
| func writeRaw(w *textWriter, b []byte) error { | ||||
| 	if err := w.WriteByte('<'); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !w.compact { | ||||
| 		if err := w.WriteByte('\n'); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	w.indent() | ||||
| 	if err := writeUnknownStruct(w, b); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	w.unindent() | ||||
| 	if err := w.WriteByte('>'); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // writeAny writes an arbitrary field.
 | ||||
| func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { | ||||
| 	v = reflect.Indirect(v) | ||||
| 
 | ||||
| 	// Floats have special cases.
 | ||||
| 	if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { | ||||
| 		x := v.Float() | ||||
| 		var b []byte | ||||
| 		switch { | ||||
| 		case math.IsInf(x, 1): | ||||
| 			b = posInf | ||||
| 		case math.IsInf(x, -1): | ||||
| 			b = negInf | ||||
| 		case math.IsNaN(x): | ||||
| 			b = nan | ||||
| 		} | ||||
| 		if b != nil { | ||||
| 			_, err := w.Write(b) | ||||
| 			return err | ||||
| 		} | ||||
| 		// Other values are handled below.
 | ||||
| 	} | ||||
| 
 | ||||
| 	// We don't attempt to serialise every possible value type; only those
 | ||||
| 	// that can occur in protocol buffers.
 | ||||
| 	switch v.Kind() { | ||||
| 	case reflect.Slice: | ||||
| 		// Should only be a []byte; repeated fields are handled in writeStruct.
 | ||||
| 		if err := writeString(w, string(v.Bytes())); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case reflect.String: | ||||
| 		if err := writeString(w, v.String()); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case reflect.Struct: | ||||
| 		// Required/optional group/message.
 | ||||
| 		var bra, ket byte = '<', '>' | ||||
| 		if props != nil && props.Wire == "group" { | ||||
| 			bra, ket = '{', '}' | ||||
| 		} | ||||
| 		if err := w.WriteByte(bra); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if !w.compact { | ||||
| 			if err := w.WriteByte('\n'); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		w.indent() | ||||
| 		if etm, ok := v.Interface().(encoding.TextMarshaler); ok { | ||||
| 			text, err := etm.MarshalText() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if _, err = w.Write(text); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else if err := tm.writeStruct(w, v); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		w.unindent() | ||||
| 		if err := w.WriteByte(ket); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	default: | ||||
| 		_, err := fmt.Fprint(w, v.Interface()) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // equivalent to C's isprint.
 | ||||
| func isprint(c byte) bool { | ||||
| 	return c >= 0x20 && c < 0x7f | ||||
| } | ||||
| 
 | ||||
| // writeString writes a string in the protocol buffer text format.
 | ||||
| // It is similar to strconv.Quote except we don't use Go escape sequences,
 | ||||
| // we treat the string as a byte sequence, and we use octal escapes.
 | ||||
| // These differences are to maintain interoperability with the other
 | ||||
| // languages' implementations of the text format.
 | ||||
| func writeString(w *textWriter, s string) error { | ||||
| 	// use WriteByte here to get any needed indent
 | ||||
| 	if err := w.WriteByte('"'); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// Loop over the bytes, not the runes.
 | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		var err error | ||||
| 		// Divergence from C++: we don't escape apostrophes.
 | ||||
| 		// There's no need to escape them, and the C++ parser
 | ||||
| 		// copes with a naked apostrophe.
 | ||||
| 		switch c := s[i]; c { | ||||
| 		case '\n': | ||||
| 			_, err = w.w.Write(backslashN) | ||||
| 		case '\r': | ||||
| 			_, err = w.w.Write(backslashR) | ||||
| 		case '\t': | ||||
| 			_, err = w.w.Write(backslashT) | ||||
| 		case '"': | ||||
| 			_, err = w.w.Write(backslashDQ) | ||||
| 		case '\\': | ||||
| 			_, err = w.w.Write(backslashBS) | ||||
| 		default: | ||||
| 			if isprint(c) { | ||||
| 				err = w.w.WriteByte(c) | ||||
| 			} else { | ||||
| 				_, err = fmt.Fprintf(w.w, "\\%03o", c) | ||||
| 			} | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return w.WriteByte('"') | ||||
| } | ||||
| 
 | ||||
| func writeUnknownStruct(w *textWriter, data []byte) (err error) { | ||||
| 	if !w.compact { | ||||
| 		if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	b := NewBuffer(data) | ||||
| 	for b.index < len(b.buf) { | ||||
| 		x, err := b.DecodeVarint() | ||||
| 		if err != nil { | ||||
| 			_, err := fmt.Fprintf(w, "/* %v */\n", err) | ||||
| 			return err | ||||
| 		} | ||||
| 		wire, tag := x&7, x>>3 | ||||
| 		if wire == WireEndGroup { | ||||
| 			w.unindent() | ||||
| 			if _, err := w.Write(endBraceNewline); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if _, err := fmt.Fprint(w, tag); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if wire != WireStartGroup { | ||||
| 			if err := w.WriteByte(':'); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		if !w.compact || wire == WireStartGroup { | ||||
| 			if err := w.WriteByte(' '); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		switch wire { | ||||
| 		case WireBytes: | ||||
| 			buf, e := b.DecodeRawBytes(false) | ||||
| 			if e == nil { | ||||
| 				_, err = fmt.Fprintf(w, "%q", buf) | ||||
| 			} else { | ||||
| 				_, err = fmt.Fprintf(w, "/* %v */", e) | ||||
| 			} | ||||
| 		case WireFixed32: | ||||
| 			x, err = b.DecodeFixed32() | ||||
| 			err = writeUnknownInt(w, x, err) | ||||
| 		case WireFixed64: | ||||
| 			x, err = b.DecodeFixed64() | ||||
| 			err = writeUnknownInt(w, x, err) | ||||
| 		case WireStartGroup: | ||||
| 			err = w.WriteByte('{') | ||||
| 			w.indent() | ||||
| 		case WireVarint: | ||||
| 			x, err = b.DecodeVarint() | ||||
| 			err = writeUnknownInt(w, x, err) | ||||
| 		default: | ||||
| 			_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err = w.WriteByte('\n'); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func writeUnknownInt(w *textWriter, x uint64, err error) error { | ||||
| 	if err == nil { | ||||
| 		_, err = fmt.Fprint(w, x) | ||||
| 	} else { | ||||
| 		_, err = fmt.Fprintf(w, "/* %v */", err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type int32Slice []int32 | ||||
| 
 | ||||
| func (s int32Slice) Len() int           { return len(s) } | ||||
| func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } | ||||
| func (s int32Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } | ||||
| 
 | ||||
| // writeExtensions writes all the extensions in pv.
 | ||||
| // pv is assumed to be a pointer to a protocol message struct that is extendable.
 | ||||
| func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { | ||||
| 	emap := extensionMaps[pv.Type().Elem()] | ||||
| 	ep, _ := extendable(pv.Interface()) | ||||
| 
 | ||||
| 	// Order the extensions by ID.
 | ||||
| 	// This isn't strictly necessary, but it will give us
 | ||||
| 	// canonical output, which will also make testing easier.
 | ||||
| 	m, mu := ep.extensionsRead() | ||||
| 	if m == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	mu.Lock() | ||||
| 	ids := make([]int32, 0, len(m)) | ||||
| 	for id := range m { | ||||
| 		ids = append(ids, id) | ||||
| 	} | ||||
| 	sort.Sort(int32Slice(ids)) | ||||
| 	mu.Unlock() | ||||
| 
 | ||||
| 	for _, extNum := range ids { | ||||
| 		ext := m[extNum] | ||||
| 		var desc *ExtensionDesc | ||||
| 		if emap != nil { | ||||
| 			desc = emap[extNum] | ||||
| 		} | ||||
| 		if desc == nil { | ||||
| 			// Unknown extension.
 | ||||
| 			if err := writeUnknownStruct(w, ext.enc); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		pb, err := GetExtension(ep, desc) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed getting extension: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		// Repeated extensions will appear as a slice.
 | ||||
| 		if !desc.repeated() { | ||||
| 			if err := tm.writeExtension(w, desc.Name, pb); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else { | ||||
| 			v := reflect.ValueOf(pb) | ||||
| 			for i := 0; i < v.Len(); i++ { | ||||
| 				if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { | ||||
| 	if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !w.compact { | ||||
| 		if err := w.WriteByte(' '); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := w.WriteByte('\n'); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (w *textWriter) writeIndent() { | ||||
| 	if !w.complete { | ||||
| 		return | ||||
| 	} | ||||
| 	remain := w.ind * 2 | ||||
| 	for remain > 0 { | ||||
| 		n := remain | ||||
| 		if n > len(spaces) { | ||||
| 			n = len(spaces) | ||||
| 		} | ||||
| 		w.w.Write(spaces[:n]) | ||||
| 		remain -= n | ||||
| 	} | ||||
| 	w.complete = false | ||||
| } | ||||
| 
 | ||||
| // TextMarshaler is a configurable text format marshaler.
 | ||||
| type TextMarshaler struct { | ||||
| 	Compact   bool // use compact text format (one line).
 | ||||
| 	ExpandAny bool // expand google.protobuf.Any messages of known types
 | ||||
| } | ||||
| 
 | ||||
| // Marshal writes a given protocol buffer in text format.
 | ||||
| // The only errors returned are from w.
 | ||||
| func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { | ||||
| 	val := reflect.ValueOf(pb) | ||||
| 	if pb == nil || val.IsNil() { | ||||
| 		w.Write([]byte("<nil>")) | ||||
| 		return nil | ||||
| 	} | ||||
| 	var bw *bufio.Writer | ||||
| 	ww, ok := w.(writer) | ||||
| 	if !ok { | ||||
| 		bw = bufio.NewWriter(w) | ||||
| 		ww = bw | ||||
| 	} | ||||
| 	aw := &textWriter{ | ||||
| 		w:        ww, | ||||
| 		complete: true, | ||||
| 		compact:  tm.Compact, | ||||
| 	} | ||||
| 
 | ||||
| 	if etm, ok := pb.(encoding.TextMarshaler); ok { | ||||
| 		text, err := etm.MarshalText() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err = aw.Write(text); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if bw != nil { | ||||
| 			return bw.Flush() | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	// Dereference the received pointer so we don't have outer < and >.
 | ||||
| 	v := reflect.Indirect(val) | ||||
| 	if err := tm.writeStruct(aw, v); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if bw != nil { | ||||
| 		return bw.Flush() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Text is the same as Marshal, but returns the string directly.
 | ||||
| func (tm *TextMarshaler) Text(pb Message) string { | ||||
| 	var buf bytes.Buffer | ||||
| 	tm.Marshal(&buf, pb) | ||||
| 	return buf.String() | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	defaultTextMarshaler = TextMarshaler{} | ||||
| 	compactTextMarshaler = TextMarshaler{Compact: true} | ||||
| ) | ||||
| 
 | ||||
| // TODO: consider removing some of the Marshal functions below.
 | ||||
| 
 | ||||
| // MarshalText writes a given protocol buffer in text format.
 | ||||
| // The only errors returned are from w.
 | ||||
| func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } | ||||
| 
 | ||||
| // MarshalTextString is the same as MarshalText, but returns the string directly.
 | ||||
| func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } | ||||
| 
 | ||||
| // CompactText writes a given protocol buffer in compact text format (one line).
 | ||||
| func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } | ||||
| 
 | ||||
| // CompactTextString is the same as CompactText, but returns the string directly.
 | ||||
| func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } | ||||
|  | @ -0,0 +1,895 @@ | |||
| // Go support for Protocol Buffers - Google's data interchange format
 | ||||
| //
 | ||||
| // Copyright 2010 The Go Authors.  All rights reserved.
 | ||||
| // https://github.com/golang/protobuf
 | ||||
| //
 | ||||
| // Redistribution and use in source and binary forms, with or without
 | ||||
| // modification, are permitted provided that the following conditions are
 | ||||
| // met:
 | ||||
| //
 | ||||
| //     * Redistributions of source code must retain the above copyright
 | ||||
| // notice, this list of conditions and the following disclaimer.
 | ||||
| //     * Redistributions in binary form must reproduce the above
 | ||||
| // copyright notice, this list of conditions and the following disclaimer
 | ||||
| // in the documentation and/or other materials provided with the
 | ||||
| // distribution.
 | ||||
| //     * Neither the name of Google Inc. nor the names of its
 | ||||
| // contributors may be used to endorse or promote products derived from
 | ||||
| // this software without specific prior written permission.
 | ||||
| //
 | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||
| 
 | ||||
| package proto | ||||
| 
 | ||||
| // Functions for parsing the Text protocol buffer format.
 | ||||
| // TODO: message sets.
 | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
| 
 | ||||
| // Error string emitted when deserializing Any and fields are already set
 | ||||
| const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" | ||||
| 
 | ||||
| type ParseError struct { | ||||
| 	Message string | ||||
| 	Line    int // 1-based line number
 | ||||
| 	Offset  int // 0-based byte offset from start of input
 | ||||
| } | ||||
| 
 | ||||
| func (p *ParseError) Error() string { | ||||
| 	if p.Line == 1 { | ||||
| 		// show offset only for first line
 | ||||
| 		return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) | ||||
| 	} | ||||
| 	return fmt.Sprintf("line %d: %v", p.Line, p.Message) | ||||
| } | ||||
| 
 | ||||
| type token struct { | ||||
| 	value    string | ||||
| 	err      *ParseError | ||||
| 	line     int    // line number
 | ||||
| 	offset   int    // byte number from start of input, not start of line
 | ||||
| 	unquoted string // the unquoted version of value, if it was a quoted string
 | ||||
| } | ||||
| 
 | ||||
| func (t *token) String() string { | ||||
| 	if t.err == nil { | ||||
| 		return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) | ||||
| 	} | ||||
| 	return fmt.Sprintf("parse error: %v", t.err) | ||||
| } | ||||
| 
 | ||||
| type textParser struct { | ||||
| 	s            string // remaining input
 | ||||
| 	done         bool   // whether the parsing is finished (success or error)
 | ||||
| 	backed       bool   // whether back() was called
 | ||||
| 	offset, line int | ||||
| 	cur          token | ||||
| } | ||||
| 
 | ||||
| func newTextParser(s string) *textParser { | ||||
| 	p := new(textParser) | ||||
| 	p.s = s | ||||
| 	p.line = 1 | ||||
| 	p.cur.line = 1 | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| func (p *textParser) errorf(format string, a ...interface{}) *ParseError { | ||||
| 	pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} | ||||
| 	p.cur.err = pe | ||||
| 	p.done = true | ||||
| 	return pe | ||||
| } | ||||
| 
 | ||||
| // Numbers and identifiers are matched by [-+._A-Za-z0-9]
 | ||||
| func isIdentOrNumberChar(c byte) bool { | ||||
| 	switch { | ||||
| 	case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': | ||||
| 		return true | ||||
| 	case '0' <= c && c <= '9': | ||||
| 		return true | ||||
| 	} | ||||
| 	switch c { | ||||
| 	case '-', '+', '.', '_': | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func isWhitespace(c byte) bool { | ||||
| 	switch c { | ||||
| 	case ' ', '\t', '\n', '\r': | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func isQuote(c byte) bool { | ||||
| 	switch c { | ||||
| 	case '"', '\'': | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (p *textParser) skipWhitespace() { | ||||
| 	i := 0 | ||||
| 	for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { | ||||
| 		if p.s[i] == '#' { | ||||
| 			// comment; skip to end of line or input
 | ||||
| 			for i < len(p.s) && p.s[i] != '\n' { | ||||
| 				i++ | ||||
| 			} | ||||
| 			if i == len(p.s) { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if p.s[i] == '\n' { | ||||
| 			p.line++ | ||||
| 		} | ||||
| 		i++ | ||||
| 	} | ||||
| 	p.offset += i | ||||
| 	p.s = p.s[i:len(p.s)] | ||||
| 	if len(p.s) == 0 { | ||||
| 		p.done = true | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (p *textParser) advance() { | ||||
| 	// Skip whitespace
 | ||||
| 	p.skipWhitespace() | ||||
| 	if p.done { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Start of non-whitespace
 | ||||
| 	p.cur.err = nil | ||||
| 	p.cur.offset, p.cur.line = p.offset, p.line | ||||
| 	p.cur.unquoted = "" | ||||
| 	switch p.s[0] { | ||||
| 	case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': | ||||
| 		// Single symbol
 | ||||
| 		p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] | ||||
| 	case '"', '\'': | ||||
| 		// Quoted string
 | ||||
| 		i := 1 | ||||
| 		for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { | ||||
| 			if p.s[i] == '\\' && i+1 < len(p.s) { | ||||
| 				// skip escaped char
 | ||||
| 				i++ | ||||
| 			} | ||||
| 			i++ | ||||
| 		} | ||||
| 		if i >= len(p.s) || p.s[i] != p.s[0] { | ||||
| 			p.errorf("unmatched quote") | ||||
| 			return | ||||
| 		} | ||||
| 		unq, err := unquoteC(p.s[1:i], rune(p.s[0])) | ||||
| 		if err != nil { | ||||
| 			p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) | ||||
| 			return | ||||
| 		} | ||||
| 		p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] | ||||
| 		p.cur.unquoted = unq | ||||
| 	default: | ||||
| 		i := 0 | ||||
| 		for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { | ||||
| 			i++ | ||||
| 		} | ||||
| 		if i == 0 { | ||||
| 			p.errorf("unexpected byte %#x", p.s[0]) | ||||
| 			return | ||||
| 		} | ||||
| 		p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] | ||||
| 	} | ||||
| 	p.offset += len(p.cur.value) | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	errBadUTF8 = errors.New("proto: bad UTF-8") | ||||
| 	errBadHex  = errors.New("proto: bad hexadecimal") | ||||
| ) | ||||
| 
 | ||||
| func unquoteC(s string, quote rune) (string, error) { | ||||
| 	// This is based on C++'s tokenizer.cc.
 | ||||
| 	// Despite its name, this is *not* parsing C syntax.
 | ||||
| 	// For instance, "\0" is an invalid quoted string.
 | ||||
| 
 | ||||
| 	// Avoid allocation in trivial cases.
 | ||||
| 	simple := true | ||||
| 	for _, r := range s { | ||||
| 		if r == '\\' || r == quote { | ||||
| 			simple = false | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if simple { | ||||
| 		return s, nil | ||||
| 	} | ||||
| 
 | ||||
| 	buf := make([]byte, 0, 3*len(s)/2) | ||||
| 	for len(s) > 0 { | ||||
| 		r, n := utf8.DecodeRuneInString(s) | ||||
| 		if r == utf8.RuneError && n == 1 { | ||||
| 			return "", errBadUTF8 | ||||
| 		} | ||||
| 		s = s[n:] | ||||
| 		if r != '\\' { | ||||
| 			if r < utf8.RuneSelf { | ||||
| 				buf = append(buf, byte(r)) | ||||
| 			} else { | ||||
| 				buf = append(buf, string(r)...) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		ch, tail, err := unescape(s) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		buf = append(buf, ch...) | ||||
| 		s = tail | ||||
| 	} | ||||
| 	return string(buf), nil | ||||
| } | ||||
| 
 | ||||
| func unescape(s string) (ch string, tail string, err error) { | ||||
| 	r, n := utf8.DecodeRuneInString(s) | ||||
| 	if r == utf8.RuneError && n == 1 { | ||||
| 		return "", "", errBadUTF8 | ||||
| 	} | ||||
| 	s = s[n:] | ||||
| 	switch r { | ||||
| 	case 'a': | ||||
| 		return "\a", s, nil | ||||
| 	case 'b': | ||||
| 		return "\b", s, nil | ||||
| 	case 'f': | ||||
| 		return "\f", s, nil | ||||
| 	case 'n': | ||||
| 		return "\n", s, nil | ||||
| 	case 'r': | ||||
| 		return "\r", s, nil | ||||
| 	case 't': | ||||
| 		return "\t", s, nil | ||||
| 	case 'v': | ||||
| 		return "\v", s, nil | ||||
| 	case '?': | ||||
| 		return "?", s, nil // trigraph workaround
 | ||||
| 	case '\'', '"', '\\': | ||||
| 		return string(r), s, nil | ||||
| 	case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': | ||||
| 		if len(s) < 2 { | ||||
| 			return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) | ||||
| 		} | ||||
| 		base := 8 | ||||
| 		ss := s[:2] | ||||
| 		s = s[2:] | ||||
| 		if r == 'x' || r == 'X' { | ||||
| 			base = 16 | ||||
| 		} else { | ||||
| 			ss = string(r) + ss | ||||
| 		} | ||||
| 		i, err := strconv.ParseUint(ss, base, 8) | ||||
| 		if err != nil { | ||||
| 			return "", "", err | ||||
| 		} | ||||
| 		return string([]byte{byte(i)}), s, nil | ||||
| 	case 'u', 'U': | ||||
| 		n := 4 | ||||
| 		if r == 'U' { | ||||
| 			n = 8 | ||||
| 		} | ||||
| 		if len(s) < n { | ||||
| 			return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) | ||||
| 		} | ||||
| 
 | ||||
| 		bs := make([]byte, n/2) | ||||
| 		for i := 0; i < n; i += 2 { | ||||
| 			a, ok1 := unhex(s[i]) | ||||
| 			b, ok2 := unhex(s[i+1]) | ||||
| 			if !ok1 || !ok2 { | ||||
| 				return "", "", errBadHex | ||||
| 			} | ||||
| 			bs[i/2] = a<<4 | b | ||||
| 		} | ||||
| 		s = s[n:] | ||||
| 		return string(bs), s, nil | ||||
| 	} | ||||
| 	return "", "", fmt.Errorf(`unknown escape \%c`, r) | ||||
| } | ||||
| 
 | ||||
| // Adapted from src/pkg/strconv/quote.go.
 | ||||
| func unhex(b byte) (v byte, ok bool) { | ||||
| 	switch { | ||||
| 	case '0' <= b && b <= '9': | ||||
| 		return b - '0', true | ||||
| 	case 'a' <= b && b <= 'f': | ||||
| 		return b - 'a' + 10, true | ||||
| 	case 'A' <= b && b <= 'F': | ||||
| 		return b - 'A' + 10, true | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| // Back off the parser by one token. Can only be done between calls to next().
 | ||||
| // It makes the next advance() a no-op.
 | ||||
| func (p *textParser) back() { p.backed = true } | ||||
| 
 | ||||
| // Advances the parser and returns the new current token.
 | ||||
| func (p *textParser) next() *token { | ||||
| 	if p.backed || p.done { | ||||
| 		p.backed = false | ||||
| 		return &p.cur | ||||
| 	} | ||||
| 	p.advance() | ||||
| 	if p.done { | ||||
| 		p.cur.value = "" | ||||
| 	} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { | ||||
| 		// Look for multiple quoted strings separated by whitespace,
 | ||||
| 		// and concatenate them.
 | ||||
| 		cat := p.cur | ||||
| 		for { | ||||
| 			p.skipWhitespace() | ||||
| 			if p.done || !isQuote(p.s[0]) { | ||||
| 				break | ||||
| 			} | ||||
| 			p.advance() | ||||
| 			if p.cur.err != nil { | ||||
| 				return &p.cur | ||||
| 			} | ||||
| 			cat.value += " " + p.cur.value | ||||
| 			cat.unquoted += p.cur.unquoted | ||||
| 		} | ||||
| 		p.done = false // parser may have seen EOF, but we want to return cat
 | ||||
| 		p.cur = cat | ||||
| 	} | ||||
| 	return &p.cur | ||||
| } | ||||
| 
 | ||||
| func (p *textParser) consumeToken(s string) error { | ||||
| 	tok := p.next() | ||||
| 	if tok.err != nil { | ||||
| 		return tok.err | ||||
| 	} | ||||
| 	if tok.value != s { | ||||
| 		p.back() | ||||
| 		return p.errorf("expected %q, found %q", s, tok.value) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Return a RequiredNotSetError indicating which required field was not set.
 | ||||
| func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { | ||||
| 	st := sv.Type() | ||||
| 	sprops := GetProperties(st) | ||||
| 	for i := 0; i < st.NumField(); i++ { | ||||
| 		if !isNil(sv.Field(i)) { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		props := sprops.Prop[i] | ||||
| 		if props.Required { | ||||
| 			return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} | ||||
| 		} | ||||
| 	} | ||||
| 	return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen
 | ||||
| } | ||||
| 
 | ||||
| // Returns the index in the struct for the named field, as well as the parsed tag properties.
 | ||||
| func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { | ||||
| 	i, ok := sprops.decoderOrigNames[name] | ||||
| 	if ok { | ||||
| 		return i, sprops.Prop[i], true | ||||
| 	} | ||||
| 	return -1, nil, false | ||||
| } | ||||
| 
 | ||||
| // Consume a ':' from the input stream (if the next token is a colon),
 | ||||
| // returning an error if a colon is needed but not present.
 | ||||
| func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { | ||||
| 	tok := p.next() | ||||
| 	if tok.err != nil { | ||||
| 		return tok.err | ||||
| 	} | ||||
| 	if tok.value != ":" { | ||||
| 		// Colon is optional when the field is a group or message.
 | ||||
| 		needColon := true | ||||
| 		switch props.Wire { | ||||
| 		case "group": | ||||
| 			needColon = false | ||||
| 		case "bytes": | ||||
| 			// A "bytes" field is either a message, a string, or a repeated field;
 | ||||
| 			// those three become *T, *string and []T respectively, so we can check for
 | ||||
| 			// this field being a pointer to a non-string.
 | ||||
| 			if typ.Kind() == reflect.Ptr { | ||||
| 				// *T or *string
 | ||||
| 				if typ.Elem().Kind() == reflect.String { | ||||
| 					break | ||||
| 				} | ||||
| 			} else if typ.Kind() == reflect.Slice { | ||||
| 				// []T or []*T
 | ||||
| 				if typ.Elem().Kind() != reflect.Ptr { | ||||
| 					break | ||||
| 				} | ||||
| 			} else if typ.Kind() == reflect.String { | ||||
| 				// The proto3 exception is for a string field,
 | ||||
| 				// which requires a colon.
 | ||||
| 				break | ||||
| 			} | ||||
| 			needColon = false | ||||
| 		} | ||||
| 		if needColon { | ||||
| 			return p.errorf("expected ':', found %q", tok.value) | ||||
| 		} | ||||
| 		p.back() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (p *textParser) readStruct(sv reflect.Value, terminator string) error { | ||||
| 	st := sv.Type() | ||||
| 	sprops := GetProperties(st) | ||||
| 	reqCount := sprops.reqCount | ||||
| 	var reqFieldErr error | ||||
| 	fieldSet := make(map[string]bool) | ||||
| 	// A struct is a sequence of "name: value", terminated by one of
 | ||||
| 	// '>' or '}', or the end of the input.  A name may also be
 | ||||
| 	// "[extension]" or "[type/url]".
 | ||||
| 	//
 | ||||
| 	// The whole struct can also be an expanded Any message, like:
 | ||||
| 	// [type/url] < ... struct contents ... >
 | ||||
| 	for { | ||||
| 		tok := p.next() | ||||
| 		if tok.err != nil { | ||||
| 			return tok.err | ||||
| 		} | ||||
| 		if tok.value == terminator { | ||||
| 			break | ||||
| 		} | ||||
| 		if tok.value == "[" { | ||||
| 			// Looks like an extension or an Any.
 | ||||
| 			//
 | ||||
| 			// TODO: Check whether we need to handle
 | ||||
| 			// namespace rooted names (e.g. ".something.Foo").
 | ||||
| 			extName, err := p.consumeExtName() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			if s := strings.LastIndex(extName, "/"); s >= 0 { | ||||
| 				// If it contains a slash, it's an Any type URL.
 | ||||
| 				messageName := extName[s+1:] | ||||
| 				mt := MessageType(messageName) | ||||
| 				if mt == nil { | ||||
| 					return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) | ||||
| 				} | ||||
| 				tok = p.next() | ||||
| 				if tok.err != nil { | ||||
| 					return tok.err | ||||
| 				} | ||||
| 				// consume an optional colon
 | ||||
| 				if tok.value == ":" { | ||||
| 					tok = p.next() | ||||
| 					if tok.err != nil { | ||||
| 						return tok.err | ||||
| 					} | ||||
| 				} | ||||
| 				var terminator string | ||||
| 				switch tok.value { | ||||
| 				case "<": | ||||
| 					terminator = ">" | ||||
| 				case "{": | ||||
| 					terminator = "}" | ||||
| 				default: | ||||
| 					return p.errorf("expected '{' or '<', found %q", tok.value) | ||||
| 				} | ||||
| 				v := reflect.New(mt.Elem()) | ||||
| 				if pe := p.readStruct(v.Elem(), terminator); pe != nil { | ||||
| 					return pe | ||||
| 				} | ||||
| 				b, err := Marshal(v.Interface().(Message)) | ||||
| 				if err != nil { | ||||
| 					return p.errorf("failed to marshal message of type %q: %v", messageName, err) | ||||
| 				} | ||||
| 				if fieldSet["type_url"] { | ||||
| 					return p.errorf(anyRepeatedlyUnpacked, "type_url") | ||||
| 				} | ||||
| 				if fieldSet["value"] { | ||||
| 					return p.errorf(anyRepeatedlyUnpacked, "value") | ||||
| 				} | ||||
| 				sv.FieldByName("TypeUrl").SetString(extName) | ||||
| 				sv.FieldByName("Value").SetBytes(b) | ||||
| 				fieldSet["type_url"] = true | ||||
| 				fieldSet["value"] = true | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			var desc *ExtensionDesc | ||||
| 			// This could be faster, but it's functional.
 | ||||
| 			// TODO: Do something smarter than a linear scan.
 | ||||
| 			for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { | ||||
| 				if d.Name == extName { | ||||
| 					desc = d | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			if desc == nil { | ||||
| 				return p.errorf("unrecognized extension %q", extName) | ||||
| 			} | ||||
| 
 | ||||
| 			props := &Properties{} | ||||
| 			props.Parse(desc.Tag) | ||||
| 
 | ||||
| 			typ := reflect.TypeOf(desc.ExtensionType) | ||||
| 			if err := p.checkForColon(props, typ); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			rep := desc.repeated() | ||||
| 
 | ||||
| 			// Read the extension structure, and set it in
 | ||||
| 			// the value we're constructing.
 | ||||
| 			var ext reflect.Value | ||||
| 			if !rep { | ||||
| 				ext = reflect.New(typ).Elem() | ||||
| 			} else { | ||||
| 				ext = reflect.New(typ.Elem()).Elem() | ||||
| 			} | ||||
| 			if err := p.readAny(ext, props); err != nil { | ||||
| 				if _, ok := err.(*RequiredNotSetError); !ok { | ||||
| 					return err | ||||
| 				} | ||||
| 				reqFieldErr = err | ||||
| 			} | ||||
| 			ep := sv.Addr().Interface().(Message) | ||||
| 			if !rep { | ||||
| 				SetExtension(ep, desc, ext.Interface()) | ||||
| 			} else { | ||||
| 				old, err := GetExtension(ep, desc) | ||||
| 				var sl reflect.Value | ||||
| 				if err == nil { | ||||
| 					sl = reflect.ValueOf(old) // existing slice
 | ||||
| 				} else { | ||||
| 					sl = reflect.MakeSlice(typ, 0, 1) | ||||
| 				} | ||||
| 				sl = reflect.Append(sl, ext) | ||||
| 				SetExtension(ep, desc, sl.Interface()) | ||||
| 			} | ||||
| 			if err := p.consumeOptionalSeparator(); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// This is a normal, non-extension field.
 | ||||
| 		name := tok.value | ||||
| 		var dst reflect.Value | ||||
| 		fi, props, ok := structFieldByName(sprops, name) | ||||
| 		if ok { | ||||
| 			dst = sv.Field(fi) | ||||
| 		} else if oop, ok := sprops.OneofTypes[name]; ok { | ||||
| 			// It is a oneof.
 | ||||
| 			props = oop.Prop | ||||
| 			nv := reflect.New(oop.Type.Elem()) | ||||
| 			dst = nv.Elem().Field(0) | ||||
| 			field := sv.Field(oop.Field) | ||||
| 			if !field.IsNil() { | ||||
| 				return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) | ||||
| 			} | ||||
| 			field.Set(nv) | ||||
| 		} | ||||
| 		if !dst.IsValid() { | ||||
| 			return p.errorf("unknown field name %q in %v", name, st) | ||||
| 		} | ||||
| 
 | ||||
| 		if dst.Kind() == reflect.Map { | ||||
| 			// Consume any colon.
 | ||||
| 			if err := p.checkForColon(props, dst.Type()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Construct the map if it doesn't already exist.
 | ||||
| 			if dst.IsNil() { | ||||
| 				dst.Set(reflect.MakeMap(dst.Type())) | ||||
| 			} | ||||
| 			key := reflect.New(dst.Type().Key()).Elem() | ||||
| 			val := reflect.New(dst.Type().Elem()).Elem() | ||||
| 
 | ||||
| 			// The map entry should be this sequence of tokens:
 | ||||
| 			//	< key : KEY value : VALUE >
 | ||||
| 			// However, implementations may omit key or value, and technically
 | ||||
| 			// we should support them in any order.  See b/28924776 for a time
 | ||||
| 			// this went wrong.
 | ||||
| 
 | ||||
| 			tok := p.next() | ||||
| 			var terminator string | ||||
| 			switch tok.value { | ||||
| 			case "<": | ||||
| 				terminator = ">" | ||||
| 			case "{": | ||||
| 				terminator = "}" | ||||
| 			default: | ||||
| 				return p.errorf("expected '{' or '<', found %q", tok.value) | ||||
| 			} | ||||
| 			for { | ||||
| 				tok := p.next() | ||||
| 				if tok.err != nil { | ||||
| 					return tok.err | ||||
| 				} | ||||
| 				if tok.value == terminator { | ||||
| 					break | ||||
| 				} | ||||
| 				switch tok.value { | ||||
| 				case "key": | ||||
| 					if err := p.consumeToken(":"); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if err := p.readAny(key, props.mkeyprop); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if err := p.consumeOptionalSeparator(); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				case "value": | ||||
| 					if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if err := p.readAny(val, props.mvalprop); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if err := p.consumeOptionalSeparator(); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				default: | ||||
| 					p.back() | ||||
| 					return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			dst.SetMapIndex(key, val) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Check that it's not already set if it's not a repeated field.
 | ||||
| 		if !props.Repeated && fieldSet[name] { | ||||
| 			return p.errorf("non-repeated field %q was repeated", name) | ||||
| 		} | ||||
| 
 | ||||
| 		if err := p.checkForColon(props, dst.Type()); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		// Parse into the field.
 | ||||
| 		fieldSet[name] = true | ||||
| 		if err := p.readAny(dst, props); err != nil { | ||||
| 			if _, ok := err.(*RequiredNotSetError); !ok { | ||||
| 				return err | ||||
| 			} | ||||
| 			reqFieldErr = err | ||||
| 		} | ||||
| 		if props.Required { | ||||
| 			reqCount-- | ||||
| 		} | ||||
| 
 | ||||
| 		if err := p.consumeOptionalSeparator(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	if reqCount > 0 { | ||||
| 		return p.missingRequiredFieldError(sv) | ||||
| 	} | ||||
| 	return reqFieldErr | ||||
| } | ||||
| 
 | ||||
| // consumeExtName consumes extension name or expanded Any type URL and the
 | ||||
| // following ']'. It returns the name or URL consumed.
 | ||||
| func (p *textParser) consumeExtName() (string, error) { | ||||
| 	tok := p.next() | ||||
| 	if tok.err != nil { | ||||
| 		return "", tok.err | ||||
| 	} | ||||
| 
 | ||||
| 	// If extension name or type url is quoted, it's a single token.
 | ||||
| 	if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { | ||||
| 		name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return name, p.consumeToken("]") | ||||
| 	} | ||||
| 
 | ||||
| 	// Consume everything up to "]"
 | ||||
| 	var parts []string | ||||
| 	for tok.value != "]" { | ||||
| 		parts = append(parts, tok.value) | ||||
| 		tok = p.next() | ||||
| 		if tok.err != nil { | ||||
| 			return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) | ||||
| 		} | ||||
| 	} | ||||
| 	return strings.Join(parts, ""), nil | ||||
| } | ||||
| 
 | ||||
| // consumeOptionalSeparator consumes an optional semicolon or comma.
 | ||||
| // It is used in readStruct to provide backward compatibility.
 | ||||
| func (p *textParser) consumeOptionalSeparator() error { | ||||
| 	tok := p.next() | ||||
| 	if tok.err != nil { | ||||
| 		return tok.err | ||||
| 	} | ||||
| 	if tok.value != ";" && tok.value != "," { | ||||
| 		p.back() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (p *textParser) readAny(v reflect.Value, props *Properties) error { | ||||
| 	tok := p.next() | ||||
| 	if tok.err != nil { | ||||
| 		return tok.err | ||||
| 	} | ||||
| 	if tok.value == "" { | ||||
| 		return p.errorf("unexpected EOF") | ||||
| 	} | ||||
| 
 | ||||
| 	switch fv := v; fv.Kind() { | ||||
| 	case reflect.Slice: | ||||
| 		at := v.Type() | ||||
| 		if at.Elem().Kind() == reflect.Uint8 { | ||||
| 			// Special case for []byte
 | ||||
| 			if tok.value[0] != '"' && tok.value[0] != '\'' { | ||||
| 				// Deliberately written out here, as the error after
 | ||||
| 				// this switch statement would write "invalid []byte: ...",
 | ||||
| 				// which is not as user-friendly.
 | ||||
| 				return p.errorf("invalid string: %v", tok.value) | ||||
| 			} | ||||
| 			bytes := []byte(tok.unquoted) | ||||
| 			fv.Set(reflect.ValueOf(bytes)) | ||||
| 			return nil | ||||
| 		} | ||||
| 		// Repeated field.
 | ||||
| 		if tok.value == "[" { | ||||
| 			// Repeated field with list notation, like [1,2,3].
 | ||||
| 			for { | ||||
| 				fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) | ||||
| 				err := p.readAny(fv.Index(fv.Len()-1), props) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				tok := p.next() | ||||
| 				if tok.err != nil { | ||||
| 					return tok.err | ||||
| 				} | ||||
| 				if tok.value == "]" { | ||||
| 					break | ||||
| 				} | ||||
| 				if tok.value != "," { | ||||
| 					return p.errorf("Expected ']' or ',' found %q", tok.value) | ||||
| 				} | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		// One value of the repeated field.
 | ||||
| 		p.back() | ||||
| 		fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) | ||||
| 		return p.readAny(fv.Index(fv.Len()-1), props) | ||||
| 	case reflect.Bool: | ||||
| 		// true/1/t/True or false/f/0/False.
 | ||||
| 		switch tok.value { | ||||
| 		case "true", "1", "t", "True": | ||||
| 			fv.SetBool(true) | ||||
| 			return nil | ||||
| 		case "false", "0", "f", "False": | ||||
| 			fv.SetBool(false) | ||||
| 			return nil | ||||
| 		} | ||||
| 	case reflect.Float32, reflect.Float64: | ||||
| 		v := tok.value | ||||
| 		// Ignore 'f' for compatibility with output generated by C++, but don't
 | ||||
| 		// remove 'f' when the value is "-inf" or "inf".
 | ||||
| 		if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { | ||||
| 			v = v[:len(v)-1] | ||||
| 		} | ||||
| 		if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { | ||||
| 			fv.SetFloat(f) | ||||
| 			return nil | ||||
| 		} | ||||
| 	case reflect.Int32: | ||||
| 		if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { | ||||
| 			fv.SetInt(x) | ||||
| 			return nil | ||||
| 		} | ||||
| 
 | ||||
| 		if len(props.Enum) == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 		m, ok := enumValueMaps[props.Enum] | ||||
| 		if !ok { | ||||
| 			break | ||||
| 		} | ||||
| 		x, ok := m[tok.value] | ||||
| 		if !ok { | ||||
| 			break | ||||
| 		} | ||||
| 		fv.SetInt(int64(x)) | ||||
| 		return nil | ||||
| 	case reflect.Int64: | ||||
| 		if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { | ||||
| 			fv.SetInt(x) | ||||
| 			return nil | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Ptr: | ||||
| 		// A basic field (indirected through pointer), or a repeated message/group
 | ||||
| 		p.back() | ||||
| 		fv.Set(reflect.New(fv.Type().Elem())) | ||||
| 		return p.readAny(fv.Elem(), props) | ||||
| 	case reflect.String: | ||||
| 		if tok.value[0] == '"' || tok.value[0] == '\'' { | ||||
| 			fv.SetString(tok.unquoted) | ||||
| 			return nil | ||||
| 		} | ||||
| 	case reflect.Struct: | ||||
| 		var terminator string | ||||
| 		switch tok.value { | ||||
| 		case "{": | ||||
| 			terminator = "}" | ||||
| 		case "<": | ||||
| 			terminator = ">" | ||||
| 		default: | ||||
| 			return p.errorf("expected '{' or '<', found %q", tok.value) | ||||
| 		} | ||||
| 		// TODO: Handle nested messages which implement encoding.TextUnmarshaler.
 | ||||
| 		return p.readStruct(fv, terminator) | ||||
| 	case reflect.Uint32: | ||||
| 		if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { | ||||
| 			fv.SetUint(uint64(x)) | ||||
| 			return nil | ||||
| 		} | ||||
| 	case reflect.Uint64: | ||||
| 		if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { | ||||
| 			fv.SetUint(x) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return p.errorf("invalid %v: %v", v.Type(), tok.value) | ||||
| } | ||||
| 
 | ||||
| // UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb
 | ||||
| // before starting to unmarshal, so any existing data in pb is always removed.
 | ||||
| // If a required field is not set and no other error occurs,
 | ||||
| // UnmarshalText returns *RequiredNotSetError.
 | ||||
| func UnmarshalText(s string, pb Message) error { | ||||
| 	if um, ok := pb.(encoding.TextUnmarshaler); ok { | ||||
| 		err := um.UnmarshalText([]byte(s)) | ||||
| 		return err | ||||
| 	} | ||||
| 	pb.Reset() | ||||
| 	v := reflect.ValueOf(pb) | ||||
| 	if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { | ||||
| 		return pe | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
		Loading…
	
		Reference in New Issue