Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
75159a09
Commit
75159a09
authored
Jul 28, 2017
by
Kenton Varda
Committed by
GitHub
Jul 28, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #527 from capnproto/capnp-convert
Add new `capnp convert` command with JSON support.
parents
9b5fc00a
3bd11689
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
910 additions
and
509 deletions
+910
-509
Makefile.am
c++/Makefile.am
+1
-1
CMakeLists.txt
c++/src/capnp/CMakeLists.txt
+1
-1
any.h
c++/src/capnp/any.h
+12
-0
json.h
c++/src/capnp/compat/json.h
+5
-1
capnp-test.sh
c++/src/capnp/compiler/capnp-test.sh
+35
-0
capnp.c++
c++/src/capnp/compiler/capnp.c++
+719
-506
dynamic.h
c++/src/capnp/dynamic.h
+20
-0
schema.h
c++/src/capnp/schema.h
+28
-0
pretty.json
c++/src/capnp/testdata/pretty.json
+88
-0
short.json
c++/src/capnp/testdata/short.json
+1
-0
No files found.
c++/Makefile.am
View file @
75159a09
...
...
@@ -324,7 +324,7 @@ libcapnpc_la_SOURCES= \
bin_PROGRAMS
=
capnp capnpc-capnp capnpc-c++
capnp_LDADD
=
libcapnpc.la libcapnp.la libkj.la
$(PTHREAD_LIBS)
capnp_LDADD
=
libcapnpc.la libcapnp
-json.la libcapnp
.la libkj.la
$(PTHREAD_LIBS)
capnp_SOURCES
=
\
src/capnp/compiler/module-loader.h
\
src/capnp/compiler/module-loader.c++
\
...
...
c++/src/capnp/CMakeLists.txt
View file @
75159a09
...
...
@@ -156,7 +156,7 @@ if(NOT CAPNP_LITE)
compiler/module-loader.c++
compiler/capnp.c++
)
target_link_libraries
(
capnp_tool capnpc capnp kj
)
target_link_libraries
(
capnp_tool capnpc capnp
-json capnp
kj
)
set_target_properties
(
capnp_tool PROPERTIES OUTPUT_NAME capnp
)
set_target_properties
(
capnp_tool PROPERTIES CAPNP_INCLUDE_DIRECTORY
$<JOIN:$<BUILD_INTERFACE:
${
CMAKE_CURRENT_SOURCE_DIR
}
/..>,$<INSTALL_INTERFACE:
${
CMAKE_INSTALL_BINDIR
}
/..>>
...
...
c++/src/capnp/any.h
View file @
75159a09
...
...
@@ -461,6 +461,8 @@ public:
inline
Reader
(
T
&&
value
)
:
_reader
(
_
::
PointerHelpers
<
FromReader
<
T
>>::
getInternalReader
(
kj
::
fwd
<
T
>
(
value
)))
{}
inline
MessageSize
totalSize
()
const
{
return
_reader
.
totalSize
().
asPublic
();
}
kj
::
ArrayPtr
<
const
byte
>
getDataSection
()
{
return
_reader
.
getDataSectionAsBlob
();
}
...
...
@@ -483,6 +485,11 @@ public:
// T must be a struct type.
return
typename
T
::
Reader
(
_reader
);
}
template
<
typename
T
>
ReaderFor
<
T
>
as
(
StructSchema
schema
)
const
;
// T must be DynamicStruct. Defined in dynamic.h.
private
:
_
::
StructReader
_reader
;
...
...
@@ -529,6 +536,11 @@ public:
// T must be a struct type.
return
typename
T
::
Builder
(
_builder
);
}
template
<
typename
T
>
BuilderFor
<
T
>
as
(
StructSchema
schema
);
// T must be DynamicStruct. Defined in dynamic.h.
private
:
_
::
StructBuilder
_builder
;
friend
class
Orphanage
;
...
...
c++/src/capnp/compat/json.h
View file @
75159a09
...
...
@@ -224,10 +224,14 @@ private:
// =======================================================================================
// inline implementation details
template
<
bool
isDynamic
>
struct
EncodeImpl
;
template
<
typename
T
>
kj
::
String
JsonCodec
::
encode
(
T
&&
value
)
{
Type
type
=
Type
::
from
(
value
);
typedef
FromAny
<
kj
::
Decay
<
T
>>
Base
;
return
encode
(
DynamicValue
::
Reader
(
ReaderFor
<
Base
>
(
kj
::
fwd
<
T
>
(
value
))),
Type
::
from
<
Base
>
()
);
return
encode
(
DynamicValue
::
Reader
(
ReaderFor
<
Base
>
(
kj
::
fwd
<
T
>
(
value
))),
type
);
}
template
<
typename
T
>
...
...
c++/src/capnp/compiler/capnp-test.sh
View file @
75159a09
...
...
@@ -40,6 +40,36 @@ fi
SCHEMA
=
`
dirname
"
$0
"
`
/../test.capnp
TESTDATA
=
`
dirname
"
$0
"
`
/../testdata
# ========================================================================================
# convert
$CAPNP
convert text:binary
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/binary -
||
fail encode
$CAPNP
convert text:flat
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/flat -
||
fail encode flat
$CAPNP
convert text:packed
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/packed -
||
fail encode packed
$CAPNP
convert text:flat-packed
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/packedflat -
||
fail encode packedflat
$CAPNP
convert text:binary
$SCHEMA
TestAllTypes <
$TESTDATA
/pretty.txt | cmp
$TESTDATA
/binary -
||
fail parse pretty
$CAPNP
convert binary:text
$SCHEMA
TestAllTypes <
$TESTDATA
/binary | cmp
$TESTDATA
/pretty.txt -
||
fail decode
$CAPNP
convert flat:text
$SCHEMA
TestAllTypes <
$TESTDATA
/flat | cmp
$TESTDATA
/pretty.txt -
||
fail decode flat
$CAPNP
convert packed:text
$SCHEMA
TestAllTypes <
$TESTDATA
/packed | cmp
$TESTDATA
/pretty.txt -
||
fail decode packed
$CAPNP
convert flat-packed:text
$SCHEMA
TestAllTypes <
$TESTDATA
/packedflat | cmp
$TESTDATA
/pretty.txt -
||
fail decode packedflat
$CAPNP
convert binary:text
--short
$SCHEMA
TestAllTypes <
$TESTDATA
/binary | cmp
$TESTDATA
/short.txt -
||
fail decode short
$CAPNP
convert binary:text
$SCHEMA
TestAllTypes <
$TESTDATA
/segmented | cmp
$TESTDATA
/pretty.txt -
||
fail decode segmented
$CAPNP
convert packed:text
$SCHEMA
TestAllTypes <
$TESTDATA
/segmented-packed | cmp
$TESTDATA
/pretty.txt -
||
fail decode segmented-packed
$CAPNP
convert binary:packed <
$TESTDATA
/binary | cmp
$TESTDATA
/packed -
||
fail binary to packed
$CAPNP
convert packed:binary <
$TESTDATA
/packed | cmp
$TESTDATA
/binary -
||
fail packed to binary
$CAPNP
convert binary:json
$SCHEMA
TestAllTypes <
$TESTDATA
/binary | cmp
$TESTDATA
/pretty.json -
||
fail binary to json
$CAPNP
convert binary:json
--short
$SCHEMA
TestAllTypes <
$TESTDATA
/binary | cmp
$TESTDATA
/short.json -
||
fail binary to short json
$CAPNP
convert json:binary
$SCHEMA
TestAllTypes <
$TESTDATA
/pretty.json | cmp
$TESTDATA
/binary -
||
fail json to binary
$CAPNP
convert json:binary
$SCHEMA
TestAllTypes <
$TESTDATA
/short.json | cmp
$TESTDATA
/binary -
||
fail short json to binary
# ========================================================================================
# DEPRECATED encode/decode
$CAPNP
encode
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/binary -
||
fail encode
$CAPNP
encode
--flat
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/flat -
||
fail encode flat
$CAPNP
encode
--packed
$SCHEMA
TestAllTypes <
$TESTDATA
/short.txt | cmp
$TESTDATA
/packed -
||
fail encode packed
...
...
@@ -55,6 +85,9 @@ $CAPNP decode --short $SCHEMA TestAllTypes < $TESTDATA/binary | cmp $TESTDATA/sh
$CAPNP
decode
$SCHEMA
TestAllTypes <
$TESTDATA
/segmented | cmp
$TESTDATA
/pretty.txt -
||
fail decode segmented
$CAPNP
decode
--packed
$SCHEMA
TestAllTypes <
$TESTDATA
/segmented-packed | cmp
$TESTDATA
/pretty.txt -
||
fail decode segmented-packed
# ========================================================================================
# eval
test_eval
()
{
test
"x
`
$CAPNP
eval
$SCHEMA
$1
|
tr
-d
'\r'
`
"
=
"x
$2
"
||
fail
eval
"
$1
==
$2
"
}
...
...
@@ -67,5 +100,7 @@ test_eval globalPrintableStruct '(someText = "foo")'
test_eval TestConstants.enumConst corge
test_eval
'TestListDefaults.lists.int32ListList[2][0]'
12341234
test
"x
`
$CAPNP
eval
$SCHEMA
-ojson
globalPrintableStruct |
tr
-d
'\r'
`
"
=
"x{
\"
someText
\"
:
\"
foo
\"
}"
||
fail
eval
json
"globalPrintableStruct == {someText =
\"
foo
\"
}"
$CAPNP
compile
-ofoo
$TESTDATA
/errors.capnp.nobuild 2>&1 |
sed
-e
"s,^.*/errors[.]capnp[.]nobuild,file,g"
|
tr
-d
'\r'
|
cmp
$TESTDATA
/errors.txt -
||
fail error output
c++/src/capnp/compiler/capnp.c++
View file @
75159a09
...
...
@@ -38,6 +38,8 @@
#include <sys/types.h>
#include <capnp/serialize.h>
#include <capnp/serialize-packed.h>
#include <capnp/serialize-text.h>
#include <capnp/compat/json.h>
#include <errno.h>
#include <stdlib.h>
...
...
@@ -82,10 +84,12 @@ public:
"Generate source code from schema files."
)
.
addSubCommand
(
"id"
,
KJ_BIND_METHOD
(
*
this
,
getGenIdMain
),
"Generate a new unique ID."
)
.
addSubCommand
(
"convert"
,
KJ_BIND_METHOD
(
*
this
,
getConvertMain
),
"Convert messages between binary, text, JSON, etc."
)
.
addSubCommand
(
"decode"
,
KJ_BIND_METHOD
(
*
this
,
getDecodeMain
),
"D
ecode binary Cap'n Proto message to text.
"
)
"D
EPRECATED (use `convert`)
"
)
.
addSubCommand
(
"encode"
,
KJ_BIND_METHOD
(
*
this
,
getEncodeMain
),
"
Encode text Cap'n Proto message to binary.
"
)
"
DEPRECATED (use `convert`)
"
)
.
addSubCommand
(
"eval"
,
KJ_BIND_METHOD
(
*
this
,
getEvalMain
),
"Evaluate a const from a schema file."
);
addGlobalOptions
(
builder
);
...
...
@@ -109,6 +113,46 @@ public:
.
build
();
}
kj
::
MainFunc
getConvertMain
()
{
// Only parse the schemas we actually need for decoding.
compileEagerness
=
Compiler
::
NODE
;
// Drop annotations since we don't need them. This avoids importing files like c++.capnp.
annotationFlag
=
Compiler
::
DROP_ANNOTATIONS
;
kj
::
MainBuilder
builder
(
context
,
VERSION_STRING
,
"Convers messages between formats. Reads a stream of messages from stdin in format "
"<from> and writes them to stdout in format <to>. Valid formats are:
\n
"
" binary standard binary format
\n
"
" packed packed binary format (deflates zeroes)
\n
"
" flat binary single segment, no segment table (rare)
\n
"
" flat-packed flat and packed
\n
"
" text schema language struct literal format
\n
"
" json JSON format
\n
"
"When using
\"
text
\"
or
\"
json
\"
format, you must specify <schema-file> and <type> "
"(but they are ignored and can be omitted for binary-to-binary conversions). "
"<type> names names a struct type defined in <schema-file>, which is the root type "
"of the message(s)."
);
addGlobalOptions
(
builder
);
builder
.
addOption
({
"short"
},
KJ_BIND_METHOD
(
*
this
,
printShort
),
"Write text or JSON output in short (non-pretty) format. Each message will "
"be printed on one line, without using whitespace to improve readability."
)
.
addOptionWithArg
({
"segment-size"
},
KJ_BIND_METHOD
(
*
this
,
setSegmentSize
),
"<n>"
,
"For binary output, sets the preferred segment size on the MallocMessageBuilder to <n> "
"words and turns off heuristic growth. This flag is mainly useful "
"for testing. Without it, each message will be written as a single "
"segment."
)
.
addOption
({
"quiet"
},
KJ_BIND_METHOD
(
*
this
,
setQuiet
),
"Do not print warning messages about the input being in the wrong format. "
"Use this if you find the warnings are wrong (but also let us know so "
"we can improve them)."
)
.
expectArg
(
"<from>:<to>"
,
KJ_BIND_METHOD
(
*
this
,
setConversion
))
.
expectOptionalArg
(
"<schema-file>"
,
KJ_BIND_METHOD
(
*
this
,
addSource
))
.
expectOptionalArg
(
"<type>"
,
KJ_BIND_METHOD
(
*
this
,
setRootType
))
.
callAfterParsing
(
KJ_BIND_METHOD
(
*
this
,
convert
));
return
builder
.
build
();
}
kj
::
MainFunc
getDecodeMain
()
{
// Only parse the schemas we actually need for decoding.
compileEagerness
=
Compiler
::
NODE
;
...
...
@@ -189,6 +233,9 @@ public:
// Drop annotations since we don't need them. This avoids importing files like c++.capnp.
annotationFlag
=
Compiler
::
DROP_ANNOTATIONS
;
// Default convert to text unless -o is given.
convertTo
=
Format
::
TEXT
;
kj
::
MainBuilder
builder
(
context
,
VERSION_STRING
,
"Prints (or encodes) the value of <name>, which must be defined in <schema-file>. "
"<name> must refer to a const declaration, a field of a struct type (prints the default "
...
...
@@ -206,20 +253,19 @@ public:
"and --flat flags specify binary output, in which case the const must be of struct "
"type."
);
addGlobalOptions
(
builder
);
builder
.
addOption
({
'b'
,
"binary"
},
KJ_BIND_METHOD
(
*
this
,
codeBinary
),
"Write the output as binary instead of text, using standard Cap'n Proto "
"serialization. (This writes the message using capnp::writeMessage() "
"from <capnp/serialize.h>.)"
)
builder
.
addOptionWithArg
({
'o'
,
"output"
},
KJ_BIND_METHOD
(
*
this
,
setEvalOutputFormat
),
"<format>"
,
"Encode the output in the given format. See `capnp help convert` "
"for a list of formats. Defaults to
\"
text
\"
."
)
.
addOption
({
'b'
,
"binary"
},
KJ_BIND_METHOD
(
*
this
,
codeBinary
),
"same as -obinary"
)
.
addOption
({
"flat"
},
KJ_BIND_METHOD
(
*
this
,
codeFlat
),
"
Write the output as a flat single-segment binary message, with no framing.
"
)
"
same as -oflat
"
)
.
addOption
({
'p'
,
"packed"
},
KJ_BIND_METHOD
(
*
this
,
codePacked
),
"Write the output as packed binary instead of text, using standard Cap'n "
"Proto packing, which deflates zero-valued bytes. (This writes the "
"message using capnp::writePackedMessage() from "
"<capnp/serialize-packed.h>.)"
)
"same as -opacked"
)
.
addOption
({
"short"
},
KJ_BIND_METHOD
(
*
this
,
printShort
),
"Print in short (non-pretty) text format. The message will be printed on "
"one line, without using whitespace to improve readability."
)
"If output format is text or JSON, write in short (non-pretty) format. The "
"message will be printed on one line, without using whitespace to improve "
"readability."
)
.
expectArg
(
"<schema-file>"
,
KJ_BIND_METHOD
(
*
this
,
addSource
))
.
expectArg
(
"<name>"
,
KJ_BIND_METHOD
(
*
this
,
evalConst
));
return
builder
.
build
();
...
...
@@ -586,6 +632,469 @@ public:
return
true
;
}
// =====================================================================================
// "convert" command
private
:
enum
class
Format
{
BINARY
,
PACKED
,
FLAT
,
FLAT_PACKED
,
TEXT
,
JSON
};
kj
::
Maybe
<
Format
>
parseFormatName
(
kj
::
StringPtr
name
)
{
if
(
name
==
"binary"
)
return
Format
::
BINARY
;
if
(
name
==
"packed"
)
return
Format
::
PACKED
;
if
(
name
==
"flat"
)
return
Format
::
FLAT
;
if
(
name
==
"flat-packed"
)
return
Format
::
FLAT_PACKED
;
if
(
name
==
"text"
)
return
Format
::
TEXT
;
if
(
name
==
"json"
)
return
Format
::
JSON
;
return
nullptr
;
}
kj
::
StringPtr
toString
(
Format
format
)
{
switch
(
format
)
{
case
Format
:
:
BINARY
:
return
"binary"
;
case
Format
:
:
PACKED
:
return
"packed"
;
case
Format
:
:
FLAT
:
return
"flat"
;
case
Format
:
:
FLAT_PACKED
:
return
"flat-packed"
;
case
Format
:
:
TEXT
:
return
"text"
;
case
Format
:
:
JSON
:
return
"json"
;
}
KJ_UNREACHABLE
;
}
Format
formatFromDeprecatedFlags
(
Format
defaultFormat
)
{
// For deprecated commands "decode" and "encode".
if
(
flat
)
{
if
(
packed
)
{
return
Format
::
FLAT_PACKED
;
}
else
{
return
Format
::
FLAT
;
}
}
if
(
packed
)
{
return
Format
::
PACKED
;
}
else
if
(
binary
)
{
return
Format
::
BINARY
;
}
else
{
return
defaultFormat
;
}
}
kj
::
MainBuilder
::
Validity
verifyRequirements
(
Format
format
)
{
if
((
format
==
Format
::
TEXT
||
format
==
Format
::
JSON
)
&&
rootType
==
StructSchema
())
{
return
kj
::
str
(
"format requires schema: "
,
toString
(
format
));
}
else
{
return
true
;
}
}
public
:
kj
::
MainBuilder
::
Validity
setConversion
(
kj
::
StringPtr
conversion
)
{
KJ_IF_MAYBE
(
colon
,
conversion
.
findFirst
(
':'
))
{
auto
from
=
kj
::
str
(
conversion
.
slice
(
0
,
*
colon
));
auto
to
=
conversion
.
slice
(
*
colon
+
1
);
KJ_IF_MAYBE
(
f
,
parseFormatName
(
from
))
{
convertFrom
=
*
f
;
}
else
{
return
kj
::
str
(
"unknown format: "
,
from
);
}
KJ_IF_MAYBE
(
t
,
parseFormatName
(
to
))
{
convertTo
=
*
t
;
}
else
{
return
kj
::
str
(
"unknown format: "
,
to
);
}
return
true
;
}
else
{
return
"invalid conversion, format is: <from>:<to>"
;
}
}
kj
::
MainBuilder
::
Validity
convert
()
{
{
auto
result
=
verifyRequirements
(
convertFrom
);
if
(
result
.
getError
()
!=
nullptr
)
return
result
;
}
{
auto
result
=
verifyRequirements
(
convertTo
);
if
(
result
.
getError
()
!=
nullptr
)
return
result
;
}
kj
::
FdInputStream
rawInput
(
STDIN_FILENO
);
kj
::
BufferedInputStreamWrapper
input
(
rawInput
);
kj
::
FdOutputStream
output
(
STDOUT_FILENO
);
if
(
!
quiet
)
{
auto
result
=
checkPlausibility
(
convertFrom
,
input
.
getReadBuffer
());
if
(
result
.
getError
()
!=
nullptr
)
{
return
kj
::
mv
(
result
);
}
}
while
(
input
.
tryGetReadBuffer
().
size
()
>
0
)
{
readOneAndConvert
(
input
,
output
);
}
context
.
exit
();
KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT
;
}
private
:
kj
::
Vector
<
byte
>
readAll
(
kj
::
BufferedInputStreamWrapper
&
input
)
{
kj
::
Vector
<
byte
>
allBytes
;
for
(;;)
{
auto
buffer
=
input
.
tryGetReadBuffer
();
if
(
buffer
.
size
()
==
0
)
break
;
allBytes
.
addAll
(
buffer
);
input
.
skip
(
buffer
.
size
());
}
return
allBytes
;
}
kj
::
String
readOneText
(
kj
::
BufferedInputStreamWrapper
&
input
)
{
// Consume and return one parentheses-delimited message from the input.
//
// Accounts for nested parentheses, comments, and string literals.
enum
{
NORMAL
,
COMMENT
,
QUOTE
,
QUOTE_ESCAPE
,
DQUOTE
,
DQUOTE_ESCAPE
}
state
=
NORMAL
;
uint
depth
=
0
;
bool
sawClose
=
false
;
kj
::
Vector
<
char
>
chars
;
for
(;;)
{
auto
buffer
=
input
.
tryGetReadBuffer
();
if
(
buffer
==
nullptr
)
{
// EOF
chars
.
add
(
'\0'
);
return
kj
::
String
(
chars
.
releaseAsArray
());
}
for
(
auto
i
:
kj
::
indices
(
buffer
))
{
char
c
=
buffer
[
i
];
switch
(
state
)
{
case
NORMAL
:
switch
(
c
)
{
case
'#'
:
state
=
COMMENT
;
break
;
case
'('
:
if
(
depth
==
0
&&
sawClose
)
{
// We already got one complete message. This is the start of the next message.
// Stop here.
chars
.
addAll
(
buffer
.
slice
(
0
,
i
));
chars
.
add
(
'\0'
);
input
.
skip
(
i
);
return
kj
::
String
(
chars
.
releaseAsArray
());
}
++
depth
;
break
;
case
')'
:
if
(
depth
>
0
)
{
if
(
--
depth
==
0
)
{
sawClose
=
true
;
}
}
break
;
default
:
break
;
}
break
;
case
COMMENT
:
switch
(
c
)
{
case
'\n'
:
state
=
NORMAL
;
break
;
default
:
break
;
}
break
;
case
QUOTE
:
switch
(
c
)
{
case
'\''
:
state
=
NORMAL
;
break
;
case
'\\'
:
state
=
QUOTE_ESCAPE
;
break
;
default
:
break
;
}
break
;
case
QUOTE_ESCAPE
:
break
;
case
DQUOTE
:
switch
(
c
)
{
case
'\"'
:
state
=
NORMAL
;
break
;
case
'\\'
:
state
=
DQUOTE_ESCAPE
;
break
;
default
:
break
;
}
break
;
case
DQUOTE_ESCAPE
:
break
;
}
}
chars
.
addAll
(
buffer
);
input
.
skip
(
buffer
.
size
());
}
}
kj
::
String
readOneJson
(
kj
::
BufferedInputStreamWrapper
&
input
)
{
// Consume and return one brace-delimited message from the input.
//
// Accounts for nested braces, string literals, and comments starting with # or //. Technically
// JSON does not permit comments but this code is lenient in case we change things later.
enum
{
NORMAL
,
SLASH
,
COMMENT
,
QUOTE
,
QUOTE_ESCAPE
,
DQUOTE
,
DQUOTE_ESCAPE
}
state
=
NORMAL
;
uint
depth
=
0
;
bool
sawClose
=
false
;
kj
::
Vector
<
char
>
chars
;
for
(;;)
{
auto
buffer
=
input
.
tryGetReadBuffer
();
if
(
buffer
==
nullptr
)
{
// EOF
chars
.
add
(
'\0'
);
return
kj
::
String
(
chars
.
releaseAsArray
());
}
for
(
auto
i
:
kj
::
indices
(
buffer
))
{
char
c
=
buffer
[
i
];
switch
(
state
)
{
case
SLASH
:
if
(
c
==
'/'
)
{
state
=
COMMENT
;
break
;
}
// fallthrough
case
NORMAL
:
switch
(
c
)
{
case
'#'
:
state
=
COMMENT
;
break
;
case
'/'
:
state
=
SLASH
;
break
;
case
'{'
:
if
(
depth
==
0
&&
sawClose
)
{
// We already got one complete message. This is the start of the next message.
// Stop here.
chars
.
addAll
(
buffer
.
slice
(
0
,
i
));
chars
.
add
(
'\0'
);
input
.
skip
(
i
);
return
kj
::
String
(
chars
.
releaseAsArray
());
}
++
depth
;
break
;
case
'}'
:
if
(
depth
>
0
)
{
if
(
--
depth
==
0
)
{
sawClose
=
true
;
}
}
break
;
default
:
break
;
}
break
;
case
COMMENT
:
switch
(
c
)
{
case
'\n'
:
state
=
NORMAL
;
break
;
default
:
break
;
}
break
;
case
QUOTE
:
switch
(
c
)
{
case
'\''
:
state
=
NORMAL
;
break
;
case
'\\'
:
state
=
QUOTE_ESCAPE
;
break
;
default
:
break
;
}
break
;
case
QUOTE_ESCAPE
:
break
;
case
DQUOTE
:
switch
(
c
)
{
case
'\"'
:
state
=
NORMAL
;
break
;
case
'\\'
:
state
=
DQUOTE_ESCAPE
;
break
;
default
:
break
;
}
break
;
case
DQUOTE_ESCAPE
:
break
;
}
}
chars
.
addAll
(
buffer
);
input
.
skip
(
buffer
.
size
());
}
}
class
ParseErrorCatcher
:
public
kj
::
ExceptionCallback
{
public
:
ParseErrorCatcher
(
kj
::
ProcessContext
&
context
)
:
context
(
context
)
{}
~
ParseErrorCatcher
()
noexcept
(
false
)
{
if
(
!
unwindDetector
.
isUnwinding
())
{
KJ_IF_MAYBE
(
e
,
exception
)
{
context
.
error
(
kj
::
str
(
"*** ERROR CONVERTING PREVIOUS MESSAGE ***
\n
"
"The following error occurred while converting the message above.
\n
"
"This probably means the input data is invalid/corrupted.
\n
"
,
"Exception description: "
,
e
->
getDescription
(),
"
\n
"
"Code location: "
,
e
->
getFile
(),
":"
,
e
->
getLine
(),
"
\n
"
"*** END ERROR ***"
));
}
}
}
void
onRecoverableException
(
kj
::
Exception
&&
e
)
{
// Only capture the first exception, on the assumption that later exceptions are probably
// just cascading problems.
if
(
exception
==
nullptr
)
{
exception
=
kj
::
mv
(
e
);
}
}
private
:
kj
::
ProcessContext
&
context
;
kj
::
Maybe
<
kj
::
Exception
>
exception
;
kj
::
UnwindDetector
unwindDetector
;
};
void
readOneAndConvert
(
kj
::
BufferedInputStreamWrapper
&
input
,
kj
::
OutputStream
&
output
)
{
// Since this is a debug tool, lift the usual security limits. Worse case is the process
// crashes or has to be killed.
ReaderOptions
options
;
options
.
nestingLimit
=
kj
::
maxValue
;
options
.
traversalLimitInWords
=
kj
::
maxValue
;
ParseErrorCatcher
parseErrorCatcher
(
context
);
switch
(
convertFrom
)
{
case
Format
:
:
BINARY
:
{
capnp
::
InputStreamMessageReader
message
(
input
,
options
);
return
writeConversion
(
message
.
getRoot
<
AnyStruct
>
(),
output
);
}
case
Format
:
:
PACKED
:
{
capnp
::
PackedMessageReader
message
(
input
,
options
);
return
writeConversion
(
message
.
getRoot
<
AnyStruct
>
(),
output
);
}
case
Format
:
:
FLAT
:
{
auto
allBytes
=
readAll
(
input
);
// Technically we don't know if the bytes are aligned so we'd better copy them to a new
// array. Note that if we have a non-whole number of words we chop off the straggler
// bytes. This is fine because if those bytes are actually part of the message we will
// hit an error later and if they are not then who cares?
auto
words
=
kj
::
heapArray
<
word
>
(
allBytes
.
size
()
/
sizeof
(
word
));
memcpy
(
words
.
begin
(),
allBytes
.
begin
(),
words
.
size
()
*
sizeof
(
word
));
kj
::
ArrayPtr
<
const
word
>
segments
[
1
]
=
{
words
};
SegmentArrayMessageReader
message
(
segments
,
options
);
return
writeConversion
(
message
.
getRoot
<
AnyStruct
>
(),
output
);
}
case
Format
:
:
FLAT_PACKED
:
{
auto
allBytes
=
readAll
(
input
);
auto
words
=
kj
::
heapArray
<
word
>
(
computeUnpackedSizeInWords
(
allBytes
));
kj
::
ArrayInputStream
input
(
allBytes
);
capnp
::
_
::
PackedInputStream
unpacker
(
input
);
unpacker
.
read
(
words
.
asBytes
().
begin
(),
words
.
asBytes
().
size
());
word
dummy
;
KJ_ASSERT
(
unpacker
.
tryRead
(
&
dummy
,
sizeof
(
dummy
),
sizeof
(
dummy
))
==
0
);
kj
::
ArrayPtr
<
const
word
>
segments
[
1
]
=
{
words
};
SegmentArrayMessageReader
message
(
segments
,
options
);
return
writeConversion
(
message
.
getRoot
<
AnyStruct
>
(),
output
);
}
case
Format
:
:
TEXT
:
{
auto
text
=
readOneText
(
input
);
MallocMessageBuilder
message
;
TextCodec
codec
;
codec
.
setPrettyPrint
(
pretty
);
auto
root
=
message
.
initRoot
<
DynamicStruct
>
(
rootType
);
codec
.
decode
(
text
,
root
);
return
writeConversion
(
root
.
asReader
(),
output
);
}
case
Format
:
:
JSON
:
{
auto
text
=
readOneJson
(
input
);
MallocMessageBuilder
message
;
JsonCodec
codec
;
codec
.
setPrettyPrint
(
pretty
);
auto
root
=
message
.
initRoot
<
DynamicStruct
>
(
rootType
);
codec
.
decode
(
text
,
root
);
return
writeConversion
(
root
.
asReader
(),
output
);
}
}
KJ_UNREACHABLE
;
}
void
writeConversion
(
AnyStruct
::
Reader
reader
,
kj
::
OutputStream
&
output
)
{
switch
(
convertTo
)
{
case
Format
:
:
BINARY
:
{
MallocMessageBuilder
message
(
segmentSize
==
0
?
SUGGESTED_FIRST_SEGMENT_WORDS
:
segmentSize
,
segmentSize
==
0
?
SUGGESTED_ALLOCATION_STRATEGY
:
AllocationStrategy
::
FIXED_SIZE
);
message
.
setRoot
(
reader
);
capnp
::
writeMessage
(
output
,
message
);
return
;
}
case
Format
:
:
PACKED
:
{
MallocMessageBuilder
message
(
segmentSize
==
0
?
SUGGESTED_FIRST_SEGMENT_WORDS
:
segmentSize
,
segmentSize
==
0
?
SUGGESTED_ALLOCATION_STRATEGY
:
AllocationStrategy
::
FIXED_SIZE
);
message
.
setRoot
(
reader
);
capnp
::
writePackedMessage
(
output
,
message
);
return
;
}
case
Format
:
:
FLAT
:
{
auto
words
=
kj
::
heapArray
<
word
>
(
reader
.
totalSize
().
wordCount
+
1
);
memset
(
words
.
begin
(),
0
,
words
.
asBytes
().
size
());
copyToUnchecked
(
reader
,
words
);
output
.
write
(
words
.
begin
(),
words
.
asBytes
().
size
());
return
;
}
case
Format
:
:
FLAT_PACKED
:
{
auto
words
=
kj
::
heapArray
<
word
>
(
reader
.
totalSize
().
wordCount
+
1
);
memset
(
words
.
begin
(),
0
,
words
.
asBytes
().
size
());
copyToUnchecked
(
reader
,
words
);
kj
::
BufferedOutputStreamWrapper
buffered
(
output
);
capnp
::
_
::
PackedOutputStream
packed
(
buffered
);
packed
.
write
(
words
.
begin
(),
words
.
asBytes
().
size
());
return
;
}
case
Format
:
:
TEXT
:
{
TextCodec
codec
;
codec
.
setPrettyPrint
(
pretty
);
auto
text
=
codec
.
encode
(
reader
.
as
<
DynamicStruct
>
(
rootType
));
output
.
write
({
text
.
asBytes
(),
kj
::
StringPtr
(
"
\n
"
).
asBytes
()});
return
;
}
case
Format
:
:
JSON
:
{
JsonCodec
codec
;
codec
.
setPrettyPrint
(
pretty
);
auto
text
=
codec
.
encode
(
reader
.
as
<
DynamicStruct
>
(
rootType
));
output
.
write
({
text
.
asBytes
(),
kj
::
StringPtr
(
"
\n
"
).
asBytes
()});
return
;
}
}
KJ_UNREACHABLE
;
}
public
:
// =====================================================================================
// "decode" command
...
...
@@ -662,111 +1171,12 @@ private:
public
:
kj
::
MainBuilder
::
Validity
decode
()
{
kj
::
FdInputStream
rawInput
(
STDIN_FILENO
);
kj
::
BufferedInputStreamWrapper
input
(
rawInput
);
if
(
!
quiet
)
{
auto
result
=
checkPlausibility
(
input
.
getReadBuffer
());
if
(
result
.
getError
()
!=
nullptr
)
{
return
kj
::
mv
(
result
);
}
}
if
(
flat
)
{
// Read in the whole input to decode as one segment.
kj
::
Array
<
word
>
words
;
{
kj
::
Vector
<
byte
>
allBytes
;
for
(;;)
{
auto
buffer
=
input
.
tryGetReadBuffer
();
if
(
buffer
.
size
()
==
0
)
break
;
allBytes
.
addAll
(
buffer
);
input
.
skip
(
buffer
.
size
());
}
if
(
packed
)
{
words
=
kj
::
heapArray
<
word
>
(
computeUnpackedSizeInWords
(
allBytes
));
kj
::
ArrayInputStream
input
(
allBytes
);
capnp
::
_
::
PackedInputStream
unpacker
(
input
);
unpacker
.
read
(
words
.
asBytes
().
begin
(),
words
.
asBytes
().
size
());
word
dummy
;
KJ_ASSERT
(
unpacker
.
tryRead
(
&
dummy
,
sizeof
(
dummy
),
sizeof
(
dummy
))
==
0
);
}
else
{
// Technically we don't know if the bytes are aligned so we'd better copy them to a new
// array. Note that if we have a non-whole number of words we chop off the straggler
// bytes. This is fine because if those bytes are actually part of the message we will
// hit an error later and if they are not then who cares?
words
=
kj
::
heapArray
<
word
>
(
allBytes
.
size
()
/
sizeof
(
word
));
memcpy
(
words
.
begin
(),
allBytes
.
begin
(),
words
.
size
()
*
sizeof
(
word
));
}
}
kj
::
ArrayPtr
<
const
word
>
segments
=
words
;
decodeInner
<
SegmentArrayMessageReader
>
(
arrayPtr
(
&
segments
,
1
));
}
else
{
while
(
input
.
tryGetReadBuffer
().
size
()
>
0
)
{
if
(
packed
)
{
decodeInner
<
PackedMessageReader
>
(
input
);
}
else
{
decodeInner
<
InputStreamMessageReader
>
(
input
);
}
}
}
context
.
exit
();
KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT
;
convertTo
=
Format
::
TEXT
;
convertFrom
=
formatFromDeprecatedFlags
(
Format
::
BINARY
);
return
convert
();
}
private
:
struct
ParseErrorCatcher
:
public
kj
::
ExceptionCallback
{
void
onRecoverableException
(
kj
::
Exception
&&
e
)
{
// Only capture the first exception, on the assumption that later exceptions are probably
// just cascading problems.
if
(
exception
==
nullptr
)
{
exception
=
kj
::
mv
(
e
);
}
}
kj
::
Maybe
<
kj
::
Exception
>
exception
;
};
template
<
typename
MessageReaderType
,
typename
Input
>
void
decodeInner
(
Input
&&
input
)
{
// Since this is a debug tool, lift the usual security limits. Worse case is the process
// crashes or has to be killed.
ReaderOptions
options
;
options
.
nestingLimit
=
kj
::
maxValue
;
options
.
traversalLimitInWords
=
kj
::
maxValue
;
MessageReaderType
reader
(
input
,
options
);
kj
::
String
text
;
kj
::
Maybe
<
kj
::
Exception
>
exception
;
{
ParseErrorCatcher
catcher
;
auto
root
=
reader
.
template
getRoot
<
DynamicStruct
>
(
rootType
);
if
(
pretty
)
{
text
=
kj
::
str
(
prettyPrint
(
root
),
'\n'
);
}
else
{
text
=
kj
::
str
(
root
,
'\n'
);
}
exception
=
kj
::
mv
(
catcher
.
exception
);
}
kj
::
FdOutputStream
(
STDOUT_FILENO
).
write
(
text
.
begin
(),
text
.
size
());
KJ_IF_MAYBE
(
e
,
exception
)
{
context
.
error
(
kj
::
str
(
"*** ERROR DECODING PREVIOUS MESSAGE ***
\n
"
"The following error occurred while decoding the message above.
\n
"
"This probably means the input data is invalid/corrupted.
\n
"
,
"Exception description: "
,
e
->
getDescription
(),
"
\n
"
"Code location: "
,
e
->
getFile
(),
":"
,
e
->
getLine
(),
"
\n
"
"*** END ERROR ***"
));
}
}
enum
Plausibility
{
IMPOSSIBLE
,
IMPLAUSIBLE
,
...
...
@@ -935,359 +1345,226 @@ private:
});
}
kj
::
MainBuilder
::
Validity
checkPlausibility
(
kj
::
ArrayPtr
<
const
byte
>
prefix
)
{
if
(
flat
&&
packed
)
{
switch
(
isPlausiblyPackedFlat
(
prefix
))
{
case
PLAUSIBLE
:
break
;
case
IMPOSSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
return
"The input is not in --packed --flat format. It looks like it is in --packed "
"format. Try removing --flat."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyFlat
(
prefix
)))
{
return
"The input is not in --packed --flat format. It looks like it is in --flat "
"format. Try removing --packed."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
return
"The input is not in --packed --flat format. It looks like it is in regular "
"binary format. Try removing the --packed and --flat flags."
;
}
else
{
return
"The input is not a Cap'n Proto message."
;
Plausibility
isPlausiblyText
(
kj
::
ArrayPtr
<
const
byte
>
prefix
)
{
enum
{
PREAMBLE
,
COMMENT
,
BODY
}
state
;
for
(
char
c
:
prefix
.
asChars
())
{
switch
(
state
)
{
case
PREAMBLE
:
// Before opening parenthesis.
switch
(
c
)
{
case
'('
:
state
=
BODY
;
continue
;
case
'#'
:
state
=
COMMENT
;
continue
;
case
' '
:
case
'\n'
:
case
'\r'
:
case
'\t'
:
case
'\v'
:
// whitespace
break
;
default:
// Not whitespace, not comment, not open parenthesis. Impossible!
return
IMPOSSIBLE
;
}
case
IMPLAUSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --packed --flat format. It looks like
\n
"
"it may be in --packed format. I'll try to parse it in --packed --flat format
\n
"
"as you requested, but if it doesn't work, try removing --flat. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyFlat
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --packed --flat format. It looks like
\n
"
"it may be in --flat format. I'll try to parse it in --packed --flat format as
\n
"
"you requested, but if it doesn't work, try removing --packed. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --packed --flat format. It looks like
\n
"
"it may be in regular binary format. I'll try to parse it in --packed --flat
\n
"
"format as you requested, but if it doesn't work, try removing --packed and
\n
"
"--flat. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be a Cap'n Proto message in any known
\n
"
"binary format. I'll try to parse it anyway, but if it doesn't work, please
\n
"
"check your input. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
break
;
case
COMMENT
:
switch
(
c
)
{
case
'\n'
:
state
=
PREAMBLE
;
continue
;
default:
break
;
}
break
;
case
WRONG_TYPE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be the type that you specified. I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right type. This could also be because the input is not in --flat
\n
"
"format; indeed, it looks like this input may be in regular --packed format,
\n
"
"so you might want to try removing --flat. Use --quiet to suppress this
\n
"
"warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be the type that you specified. I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right type. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
case
BODY
:
switch
(
c
)
{
case
'\"'
:
case
'\''
:
// String literal. Let's stop here before things get complicated.
return
PLAUSIBLE
;
default:
break
;
}
break
;
}
}
else
if
(
flat
)
{
switch
(
isPlausiblyFlat
(
prefix
))
{
case
PLAUSIBLE
:
break
;
case
IMPOSSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
return
"The input is not in --flat format. It looks like it is in --packed format. "
"Try that instead."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyPackedFlat
(
prefix
)))
{
return
"The input is not in --flat format. It looks like it is in --packed --flat "
"format. Try adding --packed."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
return
"The input is not in --flat format. It looks like it is in regular binary "
"format. Try removing the --flat flag."
;
}
else
{
return
"The input is not a Cap'n Proto message."
;
}
case
IMPLAUSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --flat format. It looks like it may
\n
"
"be in --packed format. I'll try to parse it in --flat format as you
\n
"
"requested, but if it doesn't work, try --packed instead. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyPackedFlat
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --flat format. It looks like it may
\n
"
"be in --packed --flat format. I'll try to parse it in --flat format as you
\n
"
"requested, but if it doesn't work, try adding --packed. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --flat format. It looks like it may
\n
"
"be in regular binary format. I'll try to parse it in --flat format as you
\n
"
"requested, but if it doesn't work, try removing --flat. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be a Cap'n Proto message in any known
\n
"
"binary format. I'll try to parse it anyway, but if it doesn't work, please
\n
"
"check your input. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
if
((
c
>=
0
&&
c
<
' '
&&
c
!=
'\n'
&&
c
!=
'\r'
&&
c
!=
'\t'
&&
c
!=
'\v'
)
||
c
==
0x7f
)
{
// Unprintable character.
return
IMPOSSIBLE
;
}
}
return
PLAUSIBLE
;
}
Plausibility
isPlausiblyJson
(
kj
::
ArrayPtr
<
const
byte
>
prefix
)
{
enum
{
PREAMBLE
,
COMMENT
,
BODY
}
state
;
for
(
char
c
:
prefix
.
asChars
())
{
switch
(
state
)
{
case
PREAMBLE
:
// Before opening parenthesis.
switch
(
c
)
{
case
'{'
:
state
=
BODY
;
continue
;
case
'#'
:
state
=
COMMENT
;
continue
;
case
'/'
:
state
=
COMMENT
;
continue
;
case
' '
:
case
'\n'
:
case
'\r'
:
case
'\t'
:
case
'\v'
:
// whitespace
break
;
default:
// Not whitespace, not comment, not open brace. Impossible!
return
IMPOSSIBLE
;
}
break
;
case
WRONG_TYPE
:
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be the type that you specified. I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right type. This could also be because the input is not in --flat
\n
"
"format; indeed, it looks like this input may be in regular binary format,
\n
"
"so you might want to try removing --flat. Use --quiet to suppress this
\n
"
"warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be the type that you specified. I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right type. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
case
COMMENT
:
switch
(
c
)
{
case
'\n'
:
state
=
PREAMBLE
;
continue
;
default:
break
;
}
break
;
}
}
else
if
(
packed
)
{
switch
(
isPlausiblyPacked
(
prefix
))
{
case
PLAUSIBLE
:
break
;
case
IMPOSSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
return
"The input is not in --packed format. It looks like it is in regular binary "
"format. Try removing the --packed flag."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyPackedFlat
(
prefix
)))
{
return
"The input is not in --packed format, nor does it look like it is in regular "
"binary format. It looks like it could be in --packed --flat format, although "
"that is unusual so I could be wrong."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyFlat
(
prefix
)))
{
return
"The input is not in --packed format, nor does it look like it is in regular "
"binary format. It looks like it could be in --flat format, although that "
"is unusual so I could be wrong."
;
}
else
{
return
"The input is not a Cap'n Proto message."
;
}
case
IMPLAUSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPackedFlat
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --packed format. It looks like it may
\n
"
"be in --packed --flat format. I'll try to parse it in --packed format as you
\n
"
"requested, but if it doesn't work, try adding --flat. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --packed format. It looks like it
\n
"
"may be in regular binary format. I'll try to parse it in --packed format as
\n
"
"you requested, but if it doesn't work, try removing --packed. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyFlat
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in --packed format, nor does it look
\n
"
"like it's in regular binary format. It looks like it could be in --flat
\n
"
"format, although that is unusual so I could be wrong. I'll try to parse
\n
"
"it in --flat format as you requested, but if it doesn't work, you might
\n
"
"want to try --flat, or the data may not be Cap'n Proto at all. Use
\n
"
"--quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be a Cap'n Proto message in any known
\n
"
"binary format. I'll try to parse it anyway, but if it doesn't work, please
\n
"
"check your input. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
case
BODY
:
switch
(
c
)
{
case
'\"'
:
// String literal. Let's stop here before things get complicated.
return
PLAUSIBLE
;
default:
break
;
}
break
;
case
WRONG_TYPE
:
}
if
((
c
>
0
&&
c
<
' '
&&
c
!=
'\n'
&&
c
!=
'\r'
&&
c
!=
'\t'
&&
c
!=
'\v'
)
||
c
==
0x7f
)
{
// Unprintable character.
return
IMPOSSIBLE
;
}
}
return
PLAUSIBLE
;
}
Plausibility
isPlausibly
(
Format
format
,
kj
::
ArrayPtr
<
const
byte
>
prefix
)
{
switch
(
format
)
{
case
Format
:
:
BINARY
:
return
isPlausiblyBinary
(
prefix
);
case
Format
:
:
PACKED
:
return
isPlausiblyPacked
(
prefix
);
case
Format
:
:
FLAT
:
return
isPlausiblyFlat
(
prefix
);
case
Format
:
:
FLAT_PACKED
:
return
isPlausiblyPackedFlat
(
prefix
);
case
Format
:
:
TEXT
:
return
isPlausiblyText
(
prefix
);
case
Format
:
:
JSON
:
return
isPlausiblyJson
(
prefix
);
}
KJ_UNREACHABLE
;
}
kj
::
Maybe
<
Format
>
guessFormat
(
kj
::
ArrayPtr
<
const
byte
>
prefix
)
{
Format
candidates
[]
=
{
Format
::
BINARY
,
Format
::
TEXT
,
Format
::
PACKED
,
Format
::
JSON
,
Format
::
FLAT
,
Format
::
FLAT_PACKED
};
for
(
Format
candidate
:
candidates
)
{
if
(
plausibleOrWrongType
(
isPlausibly
(
candidate
,
prefix
)))
{
return
candidate
;
}
}
return
nullptr
;
}
kj
::
MainBuilder
::
Validity
checkPlausibility
(
Format
format
,
kj
::
ArrayPtr
<
const
byte
>
prefix
)
{
switch
(
isPlausibly
(
format
,
prefix
))
{
case
PLAUSIBLE
:
return
true
;
case
IMPOSSIBLE
:
KJ_IF_MAYBE
(
guess
,
guessFormat
(
prefix
))
{
return
kj
::
str
(
"The input is not in
\"
"
,
toString
(
format
),
"
\"
format. It looks like it is in
\"
"
,
toString
(
*
guess
),
"
\"
format. Try that instead."
);
}
else
{
return
kj
::
str
(
"The input is not in
\"
"
,
toString
(
format
),
"
\"
format."
);
}
case
IMPLAUSIBLE
:
KJ_IF_MAYBE
(
guess
,
guessFormat
(
prefix
))
{
context
.
warning
(
kj
::
str
(
"*** WARNING ***
\n
"
"The input data does not appear to be in
\"
"
,
toString
(
format
),
"
\"
format. It
\n
"
"looks like it may be in
\"
"
,
toString
(
*
guess
),
"
\"
format. I'll try to parse
\n
"
"it in
\"
"
,
toString
(
format
),
"
\"
format as you requested, but if it doesn't work,
\n
"
"try
\"
"
,
toString
(
format
),
"
\"
instead. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
));
}
else
{
context
.
warning
(
kj
::
str
(
"*** WARNING ***
\n
"
"The input data does not appear to be in
\"
"
,
toString
(
format
),
"
\"
format, nor
\n
"
"in any other known format. I'll try to parse it in
\"
"
,
toString
(
format
),
"
\"\n
"
"format anyway, as you requested. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
));
}
return
true
;
case
WRONG_TYPE
:
if
(
format
==
Format
::
FLAT
&&
plausibleOrWrongType
(
isPlausiblyBinary
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to
be the type that you specified.
I'll try
\n
"
"The input data does not appear to
match the schema that you specified.
I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right type. Use --quiet to suppress this warning.
\n
"
"have the right schema. This could also be because the input is not in
\"
flat
\"\n
"
"format; indeed, it looks like this input may be in regular binary format,
\n
"
"so you might want to try
\"
binary
\"
instead. Use --quiet to suppress this
\n
"
"warning.
\n
"
"*** END WARNING ***
\n
"
);
break
;
}
}
else
{
switch
(
isPlausiblyBinary
(
prefix
))
{
case
PLAUSIBLE
:
break
;
case
IMPOSSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
return
"The input is not in regular binary format. It looks like it is in --packed "
"format. Try adding the --packed flag."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyFlat
(
prefix
)))
{
return
"The input is not in regular binary format, nor does it look like it is in "
"--packed format. It looks like it could be in --flat format, although that "
"is unusual so I could be wrong."
;
}
else
if
(
plausibleOrWrongType
(
isPlausiblyPackedFlat
(
prefix
)))
{
return
"The input is not in regular binary format, nor does it look like it is in "
"--packed format. It looks like it could be in --packed --flat format, "
"although that is unusual so I could be wrong."
;
}
else
{
return
"The input is not a Cap'n Proto message."
;
}
case
IMPLAUSIBLE
:
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in regular binary format. It looks like
\n
"
"it may be in --packed format. I'll try to parse it in regular format as you
\n
"
"requested, but if it doesn't work, try adding --packed. Use --quiet to
\n
"
"suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in regular binary format. It looks like
\n
"
"it may be in --packed --flat format. I'll try to parse it in regular format as
\n
"
"you requested, but if it doesn't work, try adding --packed --flat. Use --quiet
\n
"
"to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
if
(
plausibleOrWrongType
(
isPlausiblyFlat
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be in regular binary format, nor does it
\n
"
"look like it's in --packed format. It looks like it could be in --flat
\n
"
"format, although that is unusual so I could be wrong. I'll try to parse
\n
"
"it in regular format as you requested, but if it doesn't work, you might
\n
"
"want to try --flat, or the data may not be Cap'n Proto at all. Use
\n
"
"--quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be a Cap'n Proto message in any known
\n
"
"binary format. I'll try to parse it anyway, but if it doesn't work, please
\n
"
"check your input. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
}
break
;
case
WRONG_TYPE
:
}
else
if
(
format
==
Format
::
FLAT_PACKED
&&
plausibleOrWrongType
(
isPlausiblyPacked
(
prefix
)))
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to match the schema that you specified. I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right schema. This could also be because the input is not in
\"
flat-packed
\"\n
"
"format; indeed, it looks like this input may be in regular packed format,
\n
"
"so you might want to try
\"
packed
\"
instead. Use --quiet to suppress this
\n
"
"warning.
\n
"
"*** END WARNING ***
\n
"
);
}
else
{
context
.
warning
(
"*** WARNING ***
\n
"
"The input data does not appear to be the type that you specified. I'll try
\n
"
"to parse it anyway, but if it doesn't look right, please verify that you
\n
"
"have the right type. Use --quiet to suppress this warning.
\n
"
"*** END WARNING ***
\n
"
);
break
;
}
}
return
true
;
}
return
true
;
KJ_UNREACHABLE
;
}
public
:
// -----------------------------------------------------------------
kj
::
MainBuilder
::
Validity
encode
()
{
kj
::
Vector
<
char
>
allText
;
{
kj
::
FdInputStream
rawInput
(
STDIN_FILENO
);
kj
::
BufferedInputStreamWrapper
input
(
rawInput
);
for
(;;)
{
auto
buf
=
input
.
tryGetReadBuffer
();
if
(
buf
.
size
()
==
0
)
break
;
allText
.
addAll
(
buf
.
asChars
());
input
.
skip
(
buf
.
size
());
}
}
EncoderErrorReporter
errorReporter
(
*
this
,
allText
);
MallocMessageBuilder
arena
;
// Lex the input.
auto
lexedTokens
=
arena
.
initRoot
<
LexedTokens
>
();
lex
(
allText
,
lexedTokens
,
errorReporter
);
// Set up the parser.
CapnpParser
parser
(
arena
.
getOrphanage
(),
errorReporter
);
auto
tokens
=
lexedTokens
.
asReader
().
getTokens
();
CapnpParser
::
ParserInput
parserInput
(
tokens
.
begin
(),
tokens
.
end
());
// Set up stuff for the ValueTranslator.
ValueResolverGlue
resolver
(
compiler
->
getLoader
(),
errorReporter
);
// Set up output stream.
kj
::
FdOutputStream
rawOutput
(
STDOUT_FILENO
);
kj
::
BufferedOutputStreamWrapper
output
(
rawOutput
);
while
(
parserInput
.
getPosition
()
!=
tokens
.
end
())
{
KJ_IF_MAYBE
(
expression
,
parser
.
getParsers
().
expression
(
parserInput
))
{
MallocMessageBuilder
item
(
segmentSize
==
0
?
SUGGESTED_FIRST_SEGMENT_WORDS
:
segmentSize
,
segmentSize
==
0
?
SUGGESTED_ALLOCATION_STRATEGY
:
AllocationStrategy
::
FIXED_SIZE
);
ValueTranslator
translator
(
resolver
,
errorReporter
,
item
.
getOrphanage
());
convertFrom
=
Format
::
TEXT
;
convertTo
=
formatFromDeprecatedFlags
(
Format
::
BINARY
);
return
convert
();
}
KJ_IF_MAYBE
(
value
,
translator
.
compileValue
(
expression
->
getReader
(),
rootType
))
{
if
(
segmentSize
==
0
)
{
writeFlat
(
value
->
getReader
().
as
<
DynamicStruct
>
(),
output
);
}
else
{
item
.
adoptRoot
(
value
->
releaseAs
<
DynamicStruct
>
());
if
(
packed
)
{
writePackedMessage
(
output
,
item
);
}
else
{
writeMessage
(
output
,
item
);
}
}
}
else
{
// Errors were reported, so we'll exit with a failure status later.
}
}
else
{
auto
best
=
parserInput
.
getBest
();
if
(
best
==
tokens
.
end
())
{
context
.
exitError
(
"Premature EOF."
);
}
else
{
errorReporter
.
addErrorOn
(
*
best
,
"Parse error."
);
context
.
exit
();
}
}
kj
::
MainBuilder
::
Validity
setEvalOutputFormat
(
kj
::
StringPtr
format
)
{
KJ_IF_MAYBE
(
f
,
parseFormatName
(
format
))
{
convertTo
=
*
f
;
return
true
;
}
else
{
return
kj
::
str
(
"unknown format: "
,
format
);
}
output
.
flush
();
context
.
exit
();
KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT
;
}
kj
::
MainBuilder
::
Validity
evalConst
(
kj
::
StringPtr
name
)
{
convertTo
=
formatFromDeprecatedFlags
(
convertTo
);
KJ_ASSERT
(
sourceFiles
.
size
()
==
1
);
auto
parser
=
kj
::
parse
::
sequence
(
...
...
@@ -1408,15 +1685,15 @@ public:
}
// OK, we have a value. Print it.
if
(
binary
||
packed
||
flat
)
{
if
(
convertTo
!=
Format
::
TEXT
)
{
if
(
value
.
getType
()
!=
DynamicValue
::
STRUCT
)
{
return
"not a struct; binary output is only available on structs"
;
}
kj
::
FdOutputStream
rawOutput
(
STDOUT_FILENO
);
kj
::
BufferedOutputStreamWrapper
output
(
rawOutput
);
writeFlat
(
value
.
as
<
DynamicStruct
>
(),
output
);
output
.
flush
(
);
auto
structValue
=
value
.
as
<
DynamicStruct
>
(
);
rootType
=
structValue
.
getSchema
(
);
kj
::
FdOutputStream
output
(
STDOUT_FILENO
);
writeConversion
(
structValue
,
output
);
context
.
exit
();
}
else
{
if
(
pretty
&&
value
.
getType
()
==
DynamicValue
::
STRUCT
)
{
...
...
@@ -1431,74 +1708,6 @@ public:
KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT
;
}
private
:
void
writeFlat
(
DynamicStruct
::
Reader
value
,
kj
::
BufferedOutputStream
&
output
)
{
// Always copy the message to a flat array so that the output is predictable (one segment,
// in canonical order).
size_t
size
=
value
.
totalSize
().
wordCount
+
1
;
kj
::
Array
<
word
>
space
=
kj
::
heapArray
<
word
>
(
size
);
memset
(
space
.
begin
(),
0
,
size
*
sizeof
(
word
));
FlatMessageBuilder
flatMessage
(
space
);
flatMessage
.
setRoot
(
value
);
flatMessage
.
requireFilled
();
if
(
flat
&&
packed
)
{
capnp
::
_
::
PackedOutputStream
packer
(
output
);
packer
.
write
(
space
.
begin
(),
space
.
size
()
*
sizeof
(
word
));
}
else
if
(
flat
)
{
output
.
write
(
space
.
begin
(),
space
.
size
()
*
sizeof
(
word
));
}
else
if
(
packed
)
{
writePackedMessage
(
output
,
flatMessage
);
}
else
{
writeMessage
(
output
,
flatMessage
);
}
}
class
EncoderErrorReporter
final
:
public
ErrorReporter
{
public
:
EncoderErrorReporter
(
GlobalErrorReporter
&
globalReporter
,
kj
::
ArrayPtr
<
const
char
>
content
)
:
globalReporter
(
globalReporter
),
lineBreaks
(
content
)
{}
void
addError
(
uint32_t
startByte
,
uint32_t
endByte
,
kj
::
StringPtr
message
)
override
{
globalReporter
.
addError
(
"<stdin>"
,
lineBreaks
.
toSourcePos
(
startByte
),
lineBreaks
.
toSourcePos
(
endByte
),
message
);
}
bool
hadErrors
()
override
{
return
globalReporter
.
hadErrors
();
}
private
:
GlobalErrorReporter
&
globalReporter
;
LineBreakTable
lineBreaks
;
};
class
ValueResolverGlue
final
:
public
ValueTranslator
::
Resolver
{
public
:
ValueResolverGlue
(
const
SchemaLoader
&
loader
,
ErrorReporter
&
errorReporter
)
:
loader
(
loader
),
errorReporter
(
errorReporter
)
{}
kj
::
Maybe
<
Schema
>
resolveType
(
uint64_t
id
)
{
// Don't use tryGet() here because we shouldn't even be here if there were compile errors.
return
loader
.
get
(
id
);
}
kj
::
Maybe
<
DynamicValue
::
Reader
>
resolveConstant
(
Expression
::
Reader
name
)
override
{
errorReporter
.
addErrorOn
(
name
,
kj
::
str
(
"External constants not allowed in encode input."
));
return
nullptr
;
}
kj
::
Maybe
<
kj
::
Array
<
const
byte
>>
readEmbed
(
LocatedText
::
Reader
filename
)
override
{
errorReporter
.
addErrorOn
(
filename
,
kj
::
str
(
"External embeds not allowed in encode input."
));
return
nullptr
;
}
private
:
const
SchemaLoader
&
loader
;
ErrorReporter
&
errorReporter
;
};
public
:
// =====================================================================================
...
...
@@ -1544,6 +1753,10 @@ private:
kj
::
Vector
<
kj
::
String
>
sourcePrefixes
;
bool
addStandardImportPaths
=
true
;
Format
convertFrom
=
Format
::
BINARY
;
Format
convertTo
=
Format
::
BINARY
;
// For the "convert" command.
bool
binary
=
false
;
bool
flat
=
false
;
bool
packed
=
false
;
...
...
c++/src/capnp/dynamic.h
View file @
75159a09
...
...
@@ -179,6 +179,8 @@ public:
template
<
typename
T
,
typename
=
kj
::
EnableIf
<
kind
<
FromReader
<
T
>>
()
==
Kind
::
STRUCT
>>
inline
Reader
(
T
&&
value
)
:
Reader
(
toDynamic
(
value
))
{}
inline
operator
AnyStruct
::
Reader
()
const
{
return
AnyStruct
::
Reader
(
reader
);
}
inline
MessageSize
totalSize
()
const
{
return
reader
.
totalSize
().
asPublic
();
}
template
<
typename
T
>
...
...
@@ -234,6 +236,7 @@ private:
friend
class
Orphan
<
DynamicStruct
>
;
friend
class
Orphan
<
DynamicValue
>
;
friend
class
Orphan
<
AnyPointer
>
;
friend
class
AnyStruct
::
Reader
;
};
class
DynamicStruct
::
Builder
{
...
...
@@ -246,6 +249,8 @@ public:
template
<
typename
T
,
typename
=
kj
::
EnableIf
<
kind
<
FromBuilder
<
T
>>
()
==
Kind
::
STRUCT
>>
inline
Builder
(
T
&&
value
)
:
Builder
(
toDynamic
(
value
))
{}
inline
operator
AnyStruct
::
Reader
()
{
return
AnyStruct
::
Builder
(
builder
);
}
inline
MessageSize
totalSize
()
const
{
return
asReader
().
totalSize
();
}
template
<
typename
T
>
...
...
@@ -323,6 +328,7 @@ private:
friend
class
Orphan
<
DynamicStruct
>
;
friend
class
Orphan
<
DynamicValue
>
;
friend
class
Orphan
<
AnyPointer
>
;
friend
class
AnyStruct
::
Builder
;
};
class
DynamicStruct
::
Pipeline
{
...
...
@@ -364,6 +370,8 @@ public:
template
<
typename
T
,
typename
=
kj
::
EnableIf
<
kind
<
FromReader
<
T
>>
()
==
Kind
::
LIST
>>
inline
Reader
(
T
&&
value
)
:
Reader
(
toDynamic
(
value
))
{}
inline
operator
AnyList
::
Reader
()
const
{
return
AnyList
::
Reader
(
reader
);
}
template
<
typename
T
>
typename
T
::
Reader
as
()
const
;
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
...
...
@@ -407,6 +415,8 @@ public:
template
<
typename
T
,
typename
=
kj
::
EnableIf
<
kind
<
FromBuilder
<
T
>>
()
==
Kind
::
LIST
>>
inline
Builder
(
T
&&
value
)
:
Builder
(
toDynamic
(
value
))
{}
inline
operator
AnyList
::
Builder
()
{
return
AnyList
::
Builder
(
builder
);
}
template
<
typename
T
>
typename
T
::
Builder
as
();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
...
...
@@ -1516,6 +1526,16 @@ inline AnyStruct::Builder DynamicStruct::Builder::as<AnyStruct>() {
return
AnyStruct
::
Builder
(
builder
);
}
template
<>
inline
DynamicStruct
::
Reader
AnyStruct
::
Reader
::
as
<
DynamicStruct
>
(
StructSchema
schema
)
const
{
return
DynamicStruct
::
Reader
(
schema
,
_reader
);
}
template
<>
inline
DynamicStruct
::
Builder
AnyStruct
::
Builder
::
as
<
DynamicStruct
>
(
StructSchema
schema
)
{
return
DynamicStruct
::
Builder
(
schema
,
_builder
);
}
template
<
typename
T
>
typename
T
::
Pipeline
DynamicStruct
::
Pipeline
::
releaseAs
()
{
static_assert
(
kind
<
T
>
()
==
Kind
::
STRUCT
,
...
...
c++/src/capnp/schema.h
View file @
75159a09
...
...
@@ -599,6 +599,8 @@ public:
template
<
typename
T
>
inline
static
Type
from
();
template
<
typename
T
>
inline
static
Type
from
(
T
&&
value
);
inline
schema
::
Type
::
Which
which
()
const
;
...
...
@@ -680,6 +682,9 @@ private:
void
requireUsableAs
(
Type
expected
)
const
;
template
<
typename
T
,
Kind
k
>
struct
FromValueImpl
;
friend
class
ListSchema
;
// only for requireUsableAs()
};
...
...
@@ -899,6 +904,29 @@ inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind(
template
<
typename
T
>
inline
Type
Type
::
from
()
{
return
Type
(
Schema
::
from
<
T
>
());
}
template
<
typename
T
,
Kind
k
>
struct
Type
::
FromValueImpl
{
template
<
typename
U
>
static
inline
Type
type
(
U
&&
value
)
{
return
Type
::
from
<
T
>
();
}
};
template
<
typename
T
>
struct
Type
::
FromValueImpl
<
T
,
Kind
::
OTHER
>
{
template
<
typename
U
>
static
inline
Type
type
(
U
&&
value
)
{
// All dynamic types have getSchema().
return
value
.
getSchema
();
}
};
template
<
typename
T
>
inline
Type
Type
::
from
(
T
&&
value
)
{
typedef
FromAny
<
kj
::
Decay
<
T
>>
Base
;
return
Type
::
FromValueImpl
<
Base
,
kind
<
Base
>
()
>::
type
(
kj
::
fwd
<
T
>
(
value
));
}
inline
bool
Type
::
isVoid
()
const
{
return
baseType
==
schema
::
Type
::
VOID
&&
listDepth
==
0
;
}
inline
bool
Type
::
isBool
()
const
{
return
baseType
==
schema
::
Type
::
BOOL
&&
listDepth
==
0
;
}
inline
bool
Type
::
isInt8
()
const
{
return
baseType
==
schema
::
Type
::
INT8
&&
listDepth
==
0
;
}
...
...
c++/src/capnp/testdata/pretty.json
0 → 100644
View file @
75159a09
{
"voidField"
:
null
,
"boolField"
:
true
,
"int8Field"
:
-123
,
"int16Field"
:
-12345
,
"int32Field"
:
-12345678
,
"int64Field"
:
"-123456789012345"
,
"uInt8Field"
:
234
,
"uInt16Field"
:
45678
,
"uInt32Field"
:
3456789012
,
"uInt64Field"
:
"12345678901234567890"
,
"float32Field"
:
1234.5
,
"float64Field"
:
-1.23e47
,
"textField"
:
"foo"
,
"dataField"
:
[
98
,
97
,
114
],
"structField"
:
{
"voidField"
:
null
,
"boolField"
:
true
,
"int8Field"
:
-12
,
"int16Field"
:
3456
,
"int32Field"
:
-78901234
,
"int64Field"
:
"56789012345678"
,
"uInt8Field"
:
90
,
"uInt16Field"
:
1234
,
"uInt32Field"
:
56789012
,
"uInt64Field"
:
"345678901234567890"
,
"float32Field"
:
-1.2499999646475857e-10
,
"float64Field"
:
345
,
"textField"
:
"baz"
,
"dataField"
:
[
113
,
117
,
120
],
"structField"
:
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"nested"
,
"structField"
:
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"really nested"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
"enumField"
:
"baz"
,
"interfaceField"
:
null
,
"voidList"
:
[
null
,
null
,
null
],
"boolList"
:
[
false
,
true
,
false
,
true
,
true
],
"int8List"
:
[
12
,
-34
,
-128
,
127
],
"int16List"
:
[
1234
,
-5678
,
-32768
,
32767
],
"int32List"
:
[
12345678
,
-90123456
,
-2147483648
,
2147483647
],
"int64List"
:
[
"123456789012345"
,
"-678901234567890"
,
"-9223372036854775808"
,
"9223372036854775807"
],
"uInt8List"
:
[
12
,
34
,
0
,
255
],
"uInt16List"
:
[
1234
,
5678
,
0
,
65535
],
"uInt32List"
:
[
12345678
,
90123456
,
0
,
4294967295
],
"uInt64List"
:
[
"123456789012345"
,
"678901234567890"
,
"0"
,
"18446744073709551615"
],
"float32List"
:
[
0
,
1234567
,
9.9999999338158125e36
,
-9.9999999338158125e36
,
9.99999991097579e-38
,
-9.99999991097579e-38
],
"float64List"
:
[
0
,
123456789012345
,
1e306
,
-1e306
,
1e-306
,
-1e-306
],
"textList"
:
[
"quux"
,
"corge"
,
"grault"
],
"dataList"
:
[[
103
,
97
,
114
,
112
,
108
,
121
],
[
119
,
97
,
108
,
100
,
111
],
[
102
,
114
,
101
,
100
]],
"structList"
:
[
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"x structlist 1"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"x structlist 2"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"x structlist 3"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
}
],
"enumList"
:
[
"qux"
,
"bar"
,
"grault"
]
},
"enumField"
:
"corge"
,
"interfaceField"
:
null
,
"voidList"
:
[
null
,
null
,
null
,
null
,
null
,
null
],
"boolList"
:
[
true
,
false
,
false
,
true
],
"int8List"
:
[
111
,
-111
],
"int16List"
:
[
11111
,
-11111
],
"int32List"
:
[
111111111
,
-111111111
],
"int64List"
:
[
"1111111111111111111"
,
"-1111111111111111111"
],
"uInt8List"
:
[
111
,
222
],
"uInt16List"
:
[
33333
,
44444
],
"uInt32List"
:
[
3333333333
],
"uInt64List"
:
[
"11111111111111111111"
],
"float32List"
:
[
5555.5
,
"Infinity"
,
"-Infinity"
,
"NaN"
],
"float64List"
:
[
7777.75
,
"Infinity"
,
"-Infinity"
,
"NaN"
],
"textList"
:
[
"plugh"
,
"xyzzy"
,
"thud"
],
"dataList"
:
[[
111
,
111
,
112
,
115
],
[
101
,
120
,
104
,
97
,
117
,
115
,
116
,
101
,
100
],
[
114
,
102
,
99
,
51
,
48
,
57
,
50
]],
"structList"
:
[
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"structlist 1"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"structlist 2"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"structlist 3"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
}
],
"enumList"
:
[
"foo"
,
"garply"
]
}
c++/src/capnp/testdata/short.json
0 → 100644
View file @
75159a09
{
"voidField"
:
null
,
"boolField"
:
true
,
"int8Field"
:
-123
,
"int16Field"
:
-12345
,
"int32Field"
:
-12345678
,
"int64Field"
:
"-123456789012345"
,
"uInt8Field"
:
234
,
"uInt16Field"
:
45678
,
"uInt32Field"
:
3456789012
,
"uInt64Field"
:
"12345678901234567890"
,
"float32Field"
:
1234.5
,
"float64Field"
:
-1.23e47
,
"textField"
:
"foo"
,
"dataField"
:[
98
,
97
,
114
],
"structField"
:{
"voidField"
:
null
,
"boolField"
:
true
,
"int8Field"
:
-12
,
"int16Field"
:
3456
,
"int32Field"
:
-78901234
,
"int64Field"
:
"56789012345678"
,
"uInt8Field"
:
90
,
"uInt16Field"
:
1234
,
"uInt32Field"
:
56789012
,
"uInt64Field"
:
"345678901234567890"
,
"float32Field"
:
-1.2499999646475857e-10
,
"float64Field"
:
345
,
"textField"
:
"baz"
,
"dataField"
:[
113
,
117
,
120
],
"structField"
:{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"nested"
,
"structField"
:{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"really nested"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
"enumField"
:
"foo"
,
"interfaceField"
:
null
},
"enumField"
:
"baz"
,
"interfaceField"
:
null
,
"voidList"
:[
null
,
null
,
null
],
"boolList"
:[
false
,
true
,
false
,
true
,
true
],
"int8List"
:[
12
,
-34
,
-128
,
127
],
"int16List"
:[
1234
,
-5678
,
-32768
,
32767
],
"int32List"
:[
12345678
,
-90123456
,
-2147483648
,
2147483647
],
"int64List"
:[
"123456789012345"
,
"-678901234567890"
,
"-9223372036854775808"
,
"9223372036854775807"
],
"uInt8List"
:[
12
,
34
,
0
,
255
],
"uInt16List"
:[
1234
,
5678
,
0
,
65535
],
"uInt32List"
:[
12345678
,
90123456
,
0
,
4294967295
],
"uInt64List"
:[
"123456789012345"
,
"678901234567890"
,
"0"
,
"18446744073709551615"
],
"float32List"
:[
0
,
1234567
,
9.9999999338158125e36
,
-9.9999999338158125e36
,
9.99999991097579e-38
,
-9.99999991097579e-38
],
"float64List"
:[
0
,
123456789012345
,
1e306
,
-1e306
,
1e-306
,
-1e-306
],
"textList"
:[
"quux"
,
"corge"
,
"grault"
],
"dataList"
:[[
103
,
97
,
114
,
112
,
108
,
121
],[
119
,
97
,
108
,
100
,
111
],[
102
,
114
,
101
,
100
]],
"structList"
:[{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"x structlist 1"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"x structlist 2"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"x structlist 3"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
}],
"enumList"
:[
"qux"
,
"bar"
,
"grault"
]},
"enumField"
:
"corge"
,
"interfaceField"
:
null
,
"voidList"
:[
null
,
null
,
null
,
null
,
null
,
null
],
"boolList"
:[
true
,
false
,
false
,
true
],
"int8List"
:[
111
,
-111
],
"int16List"
:[
11111
,
-11111
],
"int32List"
:[
111111111
,
-111111111
],
"int64List"
:[
"1111111111111111111"
,
"-1111111111111111111"
],
"uInt8List"
:[
111
,
222
],
"uInt16List"
:[
33333
,
44444
],
"uInt32List"
:[
3333333333
],
"uInt64List"
:[
"11111111111111111111"
],
"float32List"
:[
5555.5
,
"Infinity"
,
"-Infinity"
,
"NaN"
],
"float64List"
:[
7777.75
,
"Infinity"
,
"-Infinity"
,
"NaN"
],
"textList"
:[
"plugh"
,
"xyzzy"
,
"thud"
],
"dataList"
:[[
111
,
111
,
112
,
115
],[
101
,
120
,
104
,
97
,
117
,
115
,
116
,
101
,
100
],[
114
,
102
,
99
,
51
,
48
,
57
,
50
]],
"structList"
:[{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"structlist 1"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"structlist 2"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
},{
"voidField"
:
null
,
"boolField"
:
false
,
"int8Field"
:
0
,
"int16Field"
:
0
,
"int32Field"
:
0
,
"int64Field"
:
"0"
,
"uInt8Field"
:
0
,
"uInt16Field"
:
0
,
"uInt32Field"
:
0
,
"uInt64Field"
:
"0"
,
"float32Field"
:
0
,
"float64Field"
:
0
,
"textField"
:
"structlist 3"
,
"enumField"
:
"foo"
,
"interfaceField"
:
null
}],
"enumList"
:[
"foo"
,
"garply"
]}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment