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