mirror of
https://github.com/arkadiyt/protodump.git
synced 2026-10-23 18:49:38 +02:00
Add escaping
This commit is contained in:
1 parent
1a894bc290
commit
0e1bc2418e
3 files changed
+58
-14
No files matched your search
@@ -0,0 +1,13 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package escaping;
|
||||||
|
|
||||||
|
option java_package = "a\"b\\c";
|
||||||
|
option go_package = "./;escaping";
|
||||||
|
|
||||||
|
message M {
|
||||||
|
reserved "ev\"il";
|
||||||
|
optional string note = 1 [default = "evil\";\n}\nmessage Injected {\n string pwned = 1;\n}\n//"];
|
||||||
|
optional bytes blob = 2 [default = "A\377\001hi"];
|
||||||
|
}
|
||||||
|
|
||||||
+40
-10
@@ -40,6 +40,35 @@ func (pd *ProtoDefinition) write(s string) {
|
|||||||
pd.builder.WriteString(s)
|
pd.builder.WriteString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func escapeProtoString(s string) string {
|
||||||
|
var b strings.Builder
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
switch c := s[i]; {
|
||||||
|
case c == '\\':
|
||||||
|
b.WriteString(`\\`)
|
||||||
|
case c == '"':
|
||||||
|
b.WriteString(`\"`)
|
||||||
|
case c == '\n':
|
||||||
|
b.WriteString(`\n`)
|
||||||
|
case c == '\r':
|
||||||
|
b.WriteString(`\r`)
|
||||||
|
case c == '\t':
|
||||||
|
b.WriteString(`\t`)
|
||||||
|
case c < 0x20 || c >= 0x7f:
|
||||||
|
fmt.Fprintf(&b, `\%03o`, c)
|
||||||
|
default:
|
||||||
|
b.WriteByte(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pd *ProtoDefinition) writeQuoted(s string) {
|
||||||
|
pd.write("\"")
|
||||||
|
pd.write(escapeProtoString(s))
|
||||||
|
pd.write("\"")
|
||||||
|
}
|
||||||
|
|
||||||
func (pd *ProtoDefinition) String() string {
|
func (pd *ProtoDefinition) String() string {
|
||||||
return pd.builder.String()
|
return pd.builder.String()
|
||||||
}
|
}
|
||||||
@@ -143,7 +172,9 @@ func (pd *ProtoDefinition) writeField(field protoreflect.FieldDescriptor) {
|
|||||||
pd.write(" [default = ")
|
pd.write(" [default = ")
|
||||||
kind := field.Kind().String()
|
kind := field.Kind().String()
|
||||||
if kind == "string" {
|
if kind == "string" {
|
||||||
pd.write(fmt.Sprintf("\"%s\"", field.Default().String()))
|
pd.writeQuoted(field.Default().String())
|
||||||
|
} else if kind == "bytes" {
|
||||||
|
pd.writeQuoted(string(field.Default().Bytes()))
|
||||||
} else if kind == "enum" {
|
} else if kind == "enum" {
|
||||||
pd.write(string(field.DefaultEnumValue().Name()))
|
pd.write(string(field.DefaultEnumValue().Name()))
|
||||||
} else {
|
} else {
|
||||||
@@ -181,9 +212,9 @@ func (pd *ProtoDefinition) writeMessage(message protoreflect.MessageDescriptor)
|
|||||||
|
|
||||||
for i := 0; i < message.ReservedNames().Len(); i++ {
|
for i := 0; i < message.ReservedNames().Len(); i++ {
|
||||||
name := message.ReservedNames().Get(i)
|
name := message.ReservedNames().Get(i)
|
||||||
pd.writeIndented("reserved \"")
|
pd.writeIndented("reserved ")
|
||||||
pd.write(string(name))
|
pd.writeQuoted(string(name))
|
||||||
pd.write("\";\n")
|
pd.write(";\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < message.ReservedRanges().Len(); i++ {
|
for i := 0; i < message.ReservedRanges().Len(); i++ {
|
||||||
@@ -234,17 +265,16 @@ func (pd *ProtoDefinition) writeImport(fileImport protoreflect.FileImport) {
|
|||||||
if fileImport.IsPublic {
|
if fileImport.IsPublic {
|
||||||
pd.write("public ")
|
pd.write("public ")
|
||||||
}
|
}
|
||||||
pd.write("\"")
|
pd.writeQuoted(fileImport.Path())
|
||||||
pd.write(fileImport.Path())
|
pd.write(";\n")
|
||||||
pd.write("\";\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pd *ProtoDefinition) writeStringFileOptions(name string, value string) {
|
func (pd *ProtoDefinition) writeStringFileOptions(name string, value string) {
|
||||||
pd.write("option ")
|
pd.write("option ")
|
||||||
pd.write(name)
|
pd.write(name)
|
||||||
pd.write(" = \"")
|
pd.write(" = ")
|
||||||
pd.write(strings.ReplaceAll(value, "\\", "\\\\"))
|
pd.writeQuoted(value)
|
||||||
pd.write("\";\n")
|
pd.write(";\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pd *ProtoDefinition) writeBoolFileOptions(name string, value bool) {
|
func (pd *ProtoDefinition) writeBoolFileOptions(name string, value bool) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/descriptorpb"
|
"google.golang.org/protobuf/types/descriptorpb"
|
||||||
)
|
)
|
||||||
@@ -44,19 +45,19 @@ func convertProtoToFileDescriptor(filePath string) (*descriptorpb.FileDescriptor
|
|||||||
|
|
||||||
func TestDefinitions(t *testing.T) {
|
func TestDefinitions(t *testing.T) {
|
||||||
files, err := os.ReadDir(FIXTURES)
|
files, err := os.ReadDir(FIXTURES)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
t.Run(file.Name(), func(t *testing.T) {
|
t.Run(file.Name(), func(t *testing.T) {
|
||||||
filePath := path.Join(FIXTURES, file.Name())
|
filePath := path.Join(FIXTURES, file.Name())
|
||||||
descriptor, err := convertProtoToFileDescriptor(filePath)
|
descriptor, err := convertProtoToFileDescriptor(filePath)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expected, err := os.ReadFile(filePath)
|
expected, err := os.ReadFile(filePath)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
actual, err := NewFromDescriptor(descriptor)
|
actual, err := NewFromDescriptor(descriptor)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, string(expected), actual.String())
|
assert.Equal(t, string(expected), actual.String())
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in new issue
Block a user