1 : // Copyright 2011 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // JSONFileWriter is a lightweight class for writing JSON formatted output
16 : // directly to file rather than via a base::Value intermediate and then
17 : // std::string intermediate representation.
18 : #ifndef SYZYGY_CORE_JSON_FILE_WRITER_H_
19 : #define SYZYGY_CORE_JSON_FILE_WRITER_H_
20 :
21 : #include <stdint.h>
22 : #include <vector>
23 :
24 : #include "base/strings/string_piece.h"
25 :
26 : // Forward declaration.
27 : namespace base {
28 : class Value;
29 : }
30 :
31 : namespace core {
32 :
33 : // Class allowing std::ostream like output for formatted JSON serialization.
34 : // Doesn't force use of Value or std::string intermediaries like JSONWriter
35 : // does.
36 : class JSONFileWriter {
37 : public:
38 : explicit JSONFileWriter(FILE* file, bool pretty_print);
39 :
40 : ~JSONFileWriter();
41 :
42 E : bool pretty_print() const { return pretty_print_; }
43 :
44 : // Returns true if the stream is finished, and unable to accept further
45 : // data. Comments may still be output, however.
46 E : bool Finished() const { return finished_; }
47 :
48 : // For outputting comments. A comment will appear on a line by itself, with
49 : // the same indentation as the next written value. Naturally, this means that
50 : // a comment attached to a value should be written prior to that value being
51 : // output. Multiple comments may be written successively. Comments are only
52 : // output if pretty printing is enabled. It is an error to output a comment
53 : // after a dictionary key has been written, but before the corresponding
54 : // value.
55 : bool OutputComment(const base::StringPiece& comment);
56 : bool OutputComment(const base::StringPiece16& comment);
57 :
58 : // For outputting a trailing comment. Only a single trailing comment may be
59 : // written for any given line. This may only be called after having written
60 : // a value.
61 : bool OutputTrailingComment(const base::StringPiece& comment);
62 : bool OutputTrailingComment(const base::StringPiece16& comment);
63 :
64 : // For outputting lists.
65 : bool OpenList();
66 : bool CloseList();
67 :
68 : // For outputting dictionaries.
69 : bool OpenDict();
70 : bool CloseDict();
71 : bool OutputKey(const base::StringPiece& key);
72 : bool OutputKey(const base::StringPiece16& key);
73 :
74 : // Closes off the JSON stream, terminating any open data structures.
75 : // Returns true on success, false on failure.
76 : bool Flush();
77 :
78 : // For outputting simple values.
79 : bool OutputBoolean(bool value);
80 : bool OutputInteger(int value);
81 : bool OutputDouble(double value);
82 : bool OutputString(const base::StringPiece& value);
83 : bool OutputString(const base::StringPiece16& value);
84 : bool OutputNull();
85 :
86 : // For compatibility with base::Value and base::JSONWriter.
87 : bool OutputValue(const base::Value* value);
88 :
89 : protected:
90 : // Everything here is protected for unittesting purposes.
91 :
92 : // Forward declarations.
93 : enum StructureType;
94 : struct StackElement;
95 :
96 : // This class is made our friend so that we can hide some templated
97 : // implementation details in the .cc file.
98 : struct Helper;
99 : friend struct Helper;
100 :
101 : // The following group of functions are for white-space and comments, and
102 : // their behaviour is different depending on whether or not we are pretty-
103 : // printing.
104 :
105 : // Outputs the current indent.
106 : bool OutputIndent();
107 : // Outputs a new line, but only if at_col_zero_ == false and if we're pretty
108 : // printing.
109 : bool OutputNewline();
110 : // Outputs any stored comments. Will leave the alignment in the same state it
111 : // found it: if at_col_zero_ is true when entering, it will be when exiting.
112 : // If at_col_zero_ is false on entering, it assumes the current indent is
113 : // already applied, and it will apply it again before exiting.
114 : bool OutputComments();
115 : bool OutputTrailingComment();
116 : // Aligns the output cursor for a value or for dictionary key.
117 : bool AlignForValueOrKey();
118 :
119 : // For printing an actual value. These are used by the templated
120 : // implementation of the various Output* functions.
121 : bool PrintBoolean(bool value);
122 : bool PrintInteger(int value);
123 : bool PrintDouble(double value);
124 : bool PrintString(const base::StringPiece& value);
125 : bool PrintNull(int value_unused);
126 : bool PrintValue(const base::Value* value);
127 :
128 : // The following group of functions act as pass-through for fprintf and fputc,
129 : // but update internal state. No newline characters should be written using
130 : // this mechanism. All newlines should be written using OutputNewline.
131 : bool Printf(const char* format, ...);
132 : bool PutChar(char c);
133 :
134 : // Some state determination functions.
135 : bool FirstEntry() const;
136 : bool ReadyForKey() const;
137 : bool ReadyForValue() const;
138 : bool RequireKeyValue() const;
139 : bool CanClose(StructureType type) const;
140 :
141 : // Outputs the beginning of a data structure.
142 : bool OpenStructure(StructureType type);
143 : // Outputs the end of a data structure.
144 : bool CloseStructure(StructureType type);
145 : // Performs any state changes necessary after outputting a value.
146 : void FlushValue(bool value_completed);
147 :
148 : static void CompileAsserts();
149 :
150 : // The file that is being written to.
151 : FILE* file_;
152 : // Indicates whether or not we are pretty printing.
153 : bool pretty_print_;
154 : // This is set when the stream writer is finished. That is, a single value
155 : // has been fully written to the stream. No more values will be accepted.
156 : bool finished_;
157 : // This indicates whether or not we have any output on the current line.
158 : bool at_col_zero_;
159 : // Stores the current depth of indentation.
160 : size_t indent_depth_;
161 : // Stores the stack of currently opened structures.
162 : std::vector<StackElement> stack_;
163 : // Stores any comments that are due to be output. We have to keep them
164 : // around because we don't know if we need to end the previous value with
165 : // a trailing comma or not.
166 : std::string trailing_comment_;
167 : std::vector<std::string> comments_;
168 :
169 : DISALLOW_COPY_AND_ASSIGN(JSONFileWriter);
170 : };
171 :
172 : // Enumerates the type of structures that may be present in JSON data. These
173 : // are present here so that the unittests may make use of them.
174 : enum JSONFileWriter::StructureType {
175 : // Used to indicate that we are currently in a list, and awaiting a
176 : // value.
177 : kList,
178 : // Used to indicate that we are currently in a dictionary, and awaiting
179 : // a value.
180 : kDict,
181 : // Used to indicate that we a dictionary key has been output, and that
182 : // we are currently awaiting a value.
183 : kDictKey,
184 : // This must always be the last entry!
185 : kMaxStructureType
186 : };
187 :
188 : // Used for indicating the type and state of an open JSON structure.
189 : struct JSONFileWriter::StackElement {
190 E : explicit StackElement(StructureType type)
191 E : : type_(type), has_entries_(false) {
192 E : }
193 :
194 : // The type of this element.
195 : StructureType type_;
196 :
197 : // Initialized to false. Update to true if a value has been output to the
198 : // structure represented by this stack element.
199 : bool has_entries_;
200 : };
201 :
202 : } // namespace core
203 :
204 : #endif // SYZYGY_CORE_JSON_FILE_WRITER_H_
|