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