-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
storydata.go
175 lines (162 loc) · 4.36 KB
/
storydata.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
Copyright © 2014–2020 Thomas Michael Edwards. All rights reserved.
Use of this source code is governed by a Simplified BSD License which
can be found in the LICENSE file.
*/
package main
import (
"bytes"
"encoding/json"
"log"
"strings"
)
type storyDataJSON struct {
Ifid string `json:"ifid,omitempty"`
Format string `json:"format,omitempty"`
FormatVersion string `json:"format-version,omitempty"`
Options []string `json:"options,omitempty"`
Start string `json:"start,omitempty"`
TagColors twine2TagColorsMap `json:"tag-colors,omitempty"`
Zoom float64 `json:"zoom,omitempty"`
}
func (s *story) marshalStoryData() []byte {
marshaled, err := json.MarshalIndent(
&storyDataJSON{
s.ifid,
s.twine2.format,
s.twine2.formatVersion,
twine2OptionsMapToSlice(s.twine2.options),
s.twine2.start,
s.twine2.tagColors,
s.twine2.zoom,
},
"",
"\t",
)
if err != nil {
// NOTE: We should never be able to see an error here. If we do,
// then something truly exceptional—in a bad way—has happened, so
// we get our panic on.
panic(err)
}
return marshaled
}
func (s *story) unmarshalStoryData(marshaled []byte) error {
storyData := storyDataJSON{}
if err := json.Unmarshal(marshaled, &storyData); err != nil {
return err
}
s.ifid = strings.ToUpper(storyData.Ifid) // NOTE: Force uppercase for consistency.
s.twine2.format = storyData.Format
s.twine2.formatVersion = storyData.FormatVersion
s.twine2.options = twine2OptionsSliceToMap(storyData.Options)
s.twine2.start = storyData.Start
s.twine2.tagColors = storyData.TagColors
if storyData.Zoom != 0 {
s.twine2.zoom = storyData.Zoom
}
return nil
}
func twine2OptionsMapToSlice(optMap twine2OptionsMap) []string {
optSlice := []string{}
if len(optMap) > 0 {
for opt, val := range optMap {
if val {
optSlice = append(optSlice, opt)
}
}
}
return optSlice
}
func twine2OptionsSliceToMap(optSlice []string) twine2OptionsMap {
optMap := make(twine2OptionsMap)
for _, opt := range optSlice {
optMap[opt] = true
}
return optMap
}
// func (s *story) marshalStorySettings() []byte {
// var marshaled [][]byte
// for key, val := range s.twine1.settings {
// marshaled = append(marshaled, []byte(key+":"+val))
// }
// return bytes.Join(marshaled, []byte("\n"))
// }
func (s *story) unmarshalStorySettings(marshaled []byte) error {
/*
NOTE: (ca. Feb 28, 2019) Transition away from storing metadata within
the StorySettings special passage and to the StoryData special passages
for two reasons:
1. I've discovered that it's not as Twine 1-safe as I'd originally believed.
When Twine 1 imports a StorySettings passage, it does not check if fields
exist before appending "missing" fields, so it's entirely possible to end
up with the first appended field essentially being concatenated to the end
of the last of the previously existing fields. Not good.
2. Twee 3 standardization
*/
/*
LEGACY
*/
var obsolete []string
/*
END LEGACY
*/
for _, line := range bytes.Split(marshaled, []byte{'\n'}) {
line = bytes.TrimSpace(line)
if len(line) > 0 {
if i := bytes.IndexRune(line, ':'); i != -1 {
key := string(bytes.ToLower(bytes.TrimSpace(line[:i])))
val := string(bytes.ToLower(bytes.TrimSpace(line[i+1:])))
/*
LEGACY
*/
switch key {
case "ifid":
if err := validateIFID(val); err == nil {
s.legacyIFID = strings.ToUpper(val) // NOTE: Force uppercase for consistency.
}
obsolete = append(obsolete, `"ifid"`)
continue
case "zoom":
// NOTE: Just drop it.
obsolete = append(obsolete, `"zoom"`)
continue
}
/*
END LEGACY
*/
s.twine1.settings[key] = val
} else {
log.Printf(`warning: Malformed "StorySettings" entry; skipping %q.`, line)
}
}
}
/*
LEGACY
*/
if len(obsolete) > 0 {
var (
entries string
pronoun string
)
if len(obsolete) == 1 {
entries = "entry"
pronoun = "it"
} else {
entries = "entries"
pronoun = "them"
}
log.Printf(
`warning: Detected obsolete "StorySettings" %s: %s. `+
`Please remove %s from the "StorySettings" special passage. If doing `+
`so leaves the passage empty, please remove it as well.`,
entries,
strings.Join(obsolete, ", "),
pronoun,
)
}
/*
END LEGACY
*/
return nil
}