Add script/extract-cbor-rfc-7049-examples.go
diff --git a/script/extract-cbor-rfc-7049-examples.go b/script/extract-cbor-rfc-7049-examples.go
new file mode 100644
index 0000000..078b6a9
--- /dev/null
+++ b/script/extract-cbor-rfc-7049-examples.go
@@ -0,0 +1,133 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// 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
+//
+// https://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.
+
+// +build ignore
+
+package main
+
+// extract-cbor-rfc-7049-examples.go extracts the examples (Appendix A) from
+// RFC 7049 "Concise Binary Object Representation (CBOR)". Each example is
+// written to a separate file under a "cbor-rfc-7049-examples" directory.
+//
+// Usage:
+// go run extract-cbor-rfc-7049-examples.go < rfc7049-errata-corrected.txt
+//
+// The rfc7049-errata-corrected.txt file comes from
+// https://github.com/cbor/spec-with-errata-fixed
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+
+func main() {
+ if err := main1(); err != nil {
+ os.Stderr.WriteString(err.Error() + "\n")
+ os.Exit(1)
+ }
+}
+
+func main1() error {
+ src, err := readExampleTable()
+ if err != nil {
+ return err
+ }
+ if err := os.Mkdir("cbor-rfc-7049-examples", 0755); err != nil {
+ return err
+ }
+ for remaining := []byte(nil); len(src) > 0; src = remaining {
+ if i := bytes.IndexByte(src, '\n'); i >= 0 {
+ src, remaining = src[:i], src[i+1:]
+ } else {
+ remaining = nil
+ }
+ src = bytes.TrimSpace(src)
+ if (len(src) == 0) || (src[0] != '|') {
+ continue
+ }
+ if (len(src) != 69) || (src[31] != '|') || (src[68] != '|') {
+ return fmt.Errorf("main: unexpected table row: %q", string(src))
+ }
+ src = bytes.TrimSpace(src[33:68])
+ if len(src) == 0 {
+ if err := emit(); err != nil {
+ return err
+ }
+ continue
+ }
+ if (len(src) > 1) && (src[0] == '0') && (src[1] == 'x') {
+ src = src[2:]
+ }
+ for ; len(src) >= 2; src = src[2:] {
+ contents = append(contents, (unhex(src[0])<<4)|unhex(src[1]))
+ }
+ }
+ return emit()
+}
+
+var (
+ contents = []byte(nil)
+ fileNumber = 0
+)
+
+func emit() error {
+ if len(contents) == 0 {
+ return nil
+ }
+ filename := fmt.Sprintf("cbor-rfc-7049-examples/%02d.cbor", fileNumber)
+ fileNumber++
+ err := ioutil.WriteFile(filename, contents, 0644)
+ contents = nil
+ return err
+}
+
+func unhex(x uint8) uint8 {
+ if x >= 'a' {
+ return x + 10 - 'a'
+ }
+ return x - '0'
+}
+
+func readExampleTable() ([]byte, error) {
+ appendixA := []byte("Appendix A. Examples\n\n")
+ ruler := []byte("+------------------------------+------------------------------------+\n")
+
+ src, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ return nil, err
+ }
+ if i := bytes.Index(src, appendixA); i < 0 {
+ return nil, fmt.Errorf("main: couldn't find Appendix A")
+ } else {
+ src = src[i+len(appendixA):]
+ }
+ if i := bytes.Index(src, ruler); i < 0 {
+ return nil, fmt.Errorf("main: couldn't find ---- ruler")
+ } else {
+ src = src[i+len(ruler):]
+ }
+ if i := bytes.Index(src, ruler); i < 0 {
+ return nil, fmt.Errorf("main: couldn't find ---- ruler")
+ } else {
+ src = src[i+len(ruler):]
+ }
+ if i := bytes.Index(src, ruler); i < 0 {
+ return nil, fmt.Errorf("main: couldn't find Appendix B")
+ } else {
+ src = src[:i]
+ }
+ return bytes.TrimSpace(src), nil
+}