1*03ce13f7SAndroid Build Coastguard Worker // Copyright (c) 2016 Google Inc.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #ifndef TOOLS_IO_H_
16*03ce13f7SAndroid Build Coastguard Worker #define TOOLS_IO_H_
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard Worker #include <cstdint>
19*03ce13f7SAndroid Build Coastguard Worker #include <cstdio>
20*03ce13f7SAndroid Build Coastguard Worker #include <cstring>
21*03ce13f7SAndroid Build Coastguard Worker #include <vector>
22*03ce13f7SAndroid Build Coastguard Worker
23*03ce13f7SAndroid Build Coastguard Worker #if defined(SPIRV_WINDOWS)
24*03ce13f7SAndroid Build Coastguard Worker #include <fcntl.h>
25*03ce13f7SAndroid Build Coastguard Worker #include <io.h>
26*03ce13f7SAndroid Build Coastguard Worker
27*03ce13f7SAndroid Build Coastguard Worker #define SET_STDIN_TO_BINARY_MODE() _setmode(_fileno(stdin), O_BINARY);
28*03ce13f7SAndroid Build Coastguard Worker #define SET_STDIN_TO_TEXT_MODE() _setmode(_fileno(stdin), O_TEXT);
29*03ce13f7SAndroid Build Coastguard Worker #define SET_STDOUT_TO_BINARY_MODE() _setmode(_fileno(stdout), O_BINARY);
30*03ce13f7SAndroid Build Coastguard Worker #define SET_STDOUT_TO_TEXT_MODE() _setmode(_fileno(stdout), O_TEXT);
31*03ce13f7SAndroid Build Coastguard Worker #define SET_STDOUT_MODE(mode) _setmode(_fileno(stdout), mode);
32*03ce13f7SAndroid Build Coastguard Worker #else
33*03ce13f7SAndroid Build Coastguard Worker #define SET_STDIN_TO_BINARY_MODE()
34*03ce13f7SAndroid Build Coastguard Worker #define SET_STDIN_TO_TEXT_MODE()
35*03ce13f7SAndroid Build Coastguard Worker #define SET_STDOUT_TO_BINARY_MODE() 0
36*03ce13f7SAndroid Build Coastguard Worker #define SET_STDOUT_TO_TEXT_MODE() 0
37*03ce13f7SAndroid Build Coastguard Worker #define SET_STDOUT_MODE(mode)
38*03ce13f7SAndroid Build Coastguard Worker #endif
39*03ce13f7SAndroid Build Coastguard Worker
40*03ce13f7SAndroid Build Coastguard Worker // Appends the contents of the |file| to |data|, assuming each element in the
41*03ce13f7SAndroid Build Coastguard Worker // file is of type |T|.
42*03ce13f7SAndroid Build Coastguard Worker template <typename T>
ReadFile(FILE * file,std::vector<T> * data)43*03ce13f7SAndroid Build Coastguard Worker void ReadFile(FILE* file, std::vector<T>* data) {
44*03ce13f7SAndroid Build Coastguard Worker if (file == nullptr) return;
45*03ce13f7SAndroid Build Coastguard Worker
46*03ce13f7SAndroid Build Coastguard Worker const int buf_size = 1024;
47*03ce13f7SAndroid Build Coastguard Worker T buf[buf_size];
48*03ce13f7SAndroid Build Coastguard Worker while (size_t len = fread(buf, sizeof(T), buf_size, file)) {
49*03ce13f7SAndroid Build Coastguard Worker data->insert(data->end(), buf, buf + len);
50*03ce13f7SAndroid Build Coastguard Worker }
51*03ce13f7SAndroid Build Coastguard Worker }
52*03ce13f7SAndroid Build Coastguard Worker
53*03ce13f7SAndroid Build Coastguard Worker // Returns true if |file| has encountered an error opening the file or reading
54*03ce13f7SAndroid Build Coastguard Worker // the file as a series of element of type |T|. If there was an error, writes an
55*03ce13f7SAndroid Build Coastguard Worker // error message to standard error.
56*03ce13f7SAndroid Build Coastguard Worker template <class T>
WasFileCorrectlyRead(FILE * file,const char * filename)57*03ce13f7SAndroid Build Coastguard Worker bool WasFileCorrectlyRead(FILE* file, const char* filename) {
58*03ce13f7SAndroid Build Coastguard Worker if (file == nullptr) {
59*03ce13f7SAndroid Build Coastguard Worker fprintf(stderr, "error: file does not exist '%s'\n", filename);
60*03ce13f7SAndroid Build Coastguard Worker return false;
61*03ce13f7SAndroid Build Coastguard Worker }
62*03ce13f7SAndroid Build Coastguard Worker
63*03ce13f7SAndroid Build Coastguard Worker if (ftell(file) == -1L) {
64*03ce13f7SAndroid Build Coastguard Worker if (ferror(file)) {
65*03ce13f7SAndroid Build Coastguard Worker fprintf(stderr, "error: error reading file '%s'\n", filename);
66*03ce13f7SAndroid Build Coastguard Worker return false;
67*03ce13f7SAndroid Build Coastguard Worker }
68*03ce13f7SAndroid Build Coastguard Worker } else {
69*03ce13f7SAndroid Build Coastguard Worker if (sizeof(T) != 1 && (ftell(file) % sizeof(T))) {
70*03ce13f7SAndroid Build Coastguard Worker fprintf(
71*03ce13f7SAndroid Build Coastguard Worker stderr,
72*03ce13f7SAndroid Build Coastguard Worker "error: file size should be a multiple of %zd; file '%s' corrupt\n",
73*03ce13f7SAndroid Build Coastguard Worker sizeof(T), filename);
74*03ce13f7SAndroid Build Coastguard Worker return false;
75*03ce13f7SAndroid Build Coastguard Worker }
76*03ce13f7SAndroid Build Coastguard Worker }
77*03ce13f7SAndroid Build Coastguard Worker return true;
78*03ce13f7SAndroid Build Coastguard Worker }
79*03ce13f7SAndroid Build Coastguard Worker
80*03ce13f7SAndroid Build Coastguard Worker // Appends the contents of the file named |filename| to |data|, assuming
81*03ce13f7SAndroid Build Coastguard Worker // each element in the file is of type |T|. The file is opened as a binary file
82*03ce13f7SAndroid Build Coastguard Worker // If |filename| is nullptr or "-", reads from the standard input, but
83*03ce13f7SAndroid Build Coastguard Worker // reopened as a binary file. If any error occurs, writes error messages to
84*03ce13f7SAndroid Build Coastguard Worker // standard error and returns false.
85*03ce13f7SAndroid Build Coastguard Worker template <typename T>
ReadBinaryFile(const char * filename,std::vector<T> * data)86*03ce13f7SAndroid Build Coastguard Worker bool ReadBinaryFile(const char* filename, std::vector<T>* data) {
87*03ce13f7SAndroid Build Coastguard Worker const bool use_file = filename && strcmp("-", filename);
88*03ce13f7SAndroid Build Coastguard Worker FILE* fp = nullptr;
89*03ce13f7SAndroid Build Coastguard Worker if (use_file) {
90*03ce13f7SAndroid Build Coastguard Worker fp = fopen(filename, "rb");
91*03ce13f7SAndroid Build Coastguard Worker } else {
92*03ce13f7SAndroid Build Coastguard Worker SET_STDIN_TO_BINARY_MODE();
93*03ce13f7SAndroid Build Coastguard Worker fp = stdin;
94*03ce13f7SAndroid Build Coastguard Worker }
95*03ce13f7SAndroid Build Coastguard Worker
96*03ce13f7SAndroid Build Coastguard Worker ReadFile(fp, data);
97*03ce13f7SAndroid Build Coastguard Worker bool succeeded = WasFileCorrectlyRead<T>(fp, filename);
98*03ce13f7SAndroid Build Coastguard Worker if (use_file && fp) fclose(fp);
99*03ce13f7SAndroid Build Coastguard Worker return succeeded;
100*03ce13f7SAndroid Build Coastguard Worker }
101*03ce13f7SAndroid Build Coastguard Worker
102*03ce13f7SAndroid Build Coastguard Worker // Appends the contents of the file named |filename| to |data|, assuming
103*03ce13f7SAndroid Build Coastguard Worker // each element in the file is of type |T|. The file is opened as a text file
104*03ce13f7SAndroid Build Coastguard Worker // If |filename| is nullptr or "-", reads from the standard input, but
105*03ce13f7SAndroid Build Coastguard Worker // reopened as a text file. If any error occurs, writes error messages to
106*03ce13f7SAndroid Build Coastguard Worker // standard error and returns false.
107*03ce13f7SAndroid Build Coastguard Worker template <typename T>
ReadTextFile(const char * filename,std::vector<T> * data)108*03ce13f7SAndroid Build Coastguard Worker bool ReadTextFile(const char* filename, std::vector<T>* data) {
109*03ce13f7SAndroid Build Coastguard Worker const bool use_file = filename && strcmp("-", filename);
110*03ce13f7SAndroid Build Coastguard Worker FILE* fp = nullptr;
111*03ce13f7SAndroid Build Coastguard Worker if (use_file) {
112*03ce13f7SAndroid Build Coastguard Worker fp = fopen(filename, "r");
113*03ce13f7SAndroid Build Coastguard Worker } else {
114*03ce13f7SAndroid Build Coastguard Worker SET_STDIN_TO_TEXT_MODE();
115*03ce13f7SAndroid Build Coastguard Worker fp = stdin;
116*03ce13f7SAndroid Build Coastguard Worker }
117*03ce13f7SAndroid Build Coastguard Worker
118*03ce13f7SAndroid Build Coastguard Worker ReadFile(fp, data);
119*03ce13f7SAndroid Build Coastguard Worker bool succeeded = WasFileCorrectlyRead<T>(fp, filename);
120*03ce13f7SAndroid Build Coastguard Worker if (use_file && fp) fclose(fp);
121*03ce13f7SAndroid Build Coastguard Worker return succeeded;
122*03ce13f7SAndroid Build Coastguard Worker }
123*03ce13f7SAndroid Build Coastguard Worker
124*03ce13f7SAndroid Build Coastguard Worker namespace {
125*03ce13f7SAndroid Build Coastguard Worker // A class to create and manage a file for outputting data.
126*03ce13f7SAndroid Build Coastguard Worker class OutputFile {
127*03ce13f7SAndroid Build Coastguard Worker public:
128*03ce13f7SAndroid Build Coastguard Worker // Opens |filename| in the given mode. If |filename| is nullptr, the empty
129*03ce13f7SAndroid Build Coastguard Worker // string or "-", stdout will be set to the given mode.
OutputFile(const char * filename,const char * mode)130*03ce13f7SAndroid Build Coastguard Worker OutputFile(const char* filename, const char* mode) : old_mode_(0) {
131*03ce13f7SAndroid Build Coastguard Worker const bool use_stdout =
132*03ce13f7SAndroid Build Coastguard Worker !filename || (filename[0] == '-' && filename[1] == '\0');
133*03ce13f7SAndroid Build Coastguard Worker if (use_stdout) {
134*03ce13f7SAndroid Build Coastguard Worker if (strchr(mode, 'b')) {
135*03ce13f7SAndroid Build Coastguard Worker old_mode_ = SET_STDOUT_TO_BINARY_MODE();
136*03ce13f7SAndroid Build Coastguard Worker } else {
137*03ce13f7SAndroid Build Coastguard Worker old_mode_ = SET_STDOUT_TO_TEXT_MODE();
138*03ce13f7SAndroid Build Coastguard Worker }
139*03ce13f7SAndroid Build Coastguard Worker fp_ = stdout;
140*03ce13f7SAndroid Build Coastguard Worker } else {
141*03ce13f7SAndroid Build Coastguard Worker fp_ = fopen(filename, mode);
142*03ce13f7SAndroid Build Coastguard Worker }
143*03ce13f7SAndroid Build Coastguard Worker }
144*03ce13f7SAndroid Build Coastguard Worker
~OutputFile()145*03ce13f7SAndroid Build Coastguard Worker ~OutputFile() {
146*03ce13f7SAndroid Build Coastguard Worker if (fp_ == stdout) {
147*03ce13f7SAndroid Build Coastguard Worker fflush(stdout);
148*03ce13f7SAndroid Build Coastguard Worker SET_STDOUT_MODE(old_mode_);
149*03ce13f7SAndroid Build Coastguard Worker } else if (fp_ != nullptr) {
150*03ce13f7SAndroid Build Coastguard Worker fclose(fp_);
151*03ce13f7SAndroid Build Coastguard Worker }
152*03ce13f7SAndroid Build Coastguard Worker }
153*03ce13f7SAndroid Build Coastguard Worker
154*03ce13f7SAndroid Build Coastguard Worker // Returns a file handle to the file.
GetFileHandle()155*03ce13f7SAndroid Build Coastguard Worker FILE* GetFileHandle() const { return fp_; }
156*03ce13f7SAndroid Build Coastguard Worker
157*03ce13f7SAndroid Build Coastguard Worker private:
158*03ce13f7SAndroid Build Coastguard Worker FILE* fp_;
159*03ce13f7SAndroid Build Coastguard Worker int old_mode_;
160*03ce13f7SAndroid Build Coastguard Worker };
161*03ce13f7SAndroid Build Coastguard Worker } // namespace
162*03ce13f7SAndroid Build Coastguard Worker
163*03ce13f7SAndroid Build Coastguard Worker // Writes the given |data| into the file named as |filename| using the given
164*03ce13f7SAndroid Build Coastguard Worker // |mode|, assuming |data| is an array of |count| elements of type |T|. If
165*03ce13f7SAndroid Build Coastguard Worker // |filename| is nullptr or "-", writes to standard output. If any error occurs,
166*03ce13f7SAndroid Build Coastguard Worker // returns false and outputs error message to standard error.
167*03ce13f7SAndroid Build Coastguard Worker template <typename T>
WriteFile(const char * filename,const char * mode,const T * data,size_t count)168*03ce13f7SAndroid Build Coastguard Worker bool WriteFile(const char* filename, const char* mode, const T* data,
169*03ce13f7SAndroid Build Coastguard Worker size_t count) {
170*03ce13f7SAndroid Build Coastguard Worker OutputFile file(filename, mode);
171*03ce13f7SAndroid Build Coastguard Worker FILE* fp = file.GetFileHandle();
172*03ce13f7SAndroid Build Coastguard Worker if (fp == nullptr) {
173*03ce13f7SAndroid Build Coastguard Worker fprintf(stderr, "error: could not open file '%s'\n", filename);
174*03ce13f7SAndroid Build Coastguard Worker return false;
175*03ce13f7SAndroid Build Coastguard Worker }
176*03ce13f7SAndroid Build Coastguard Worker
177*03ce13f7SAndroid Build Coastguard Worker size_t written = fwrite(data, sizeof(T), count, fp);
178*03ce13f7SAndroid Build Coastguard Worker if (count != written) {
179*03ce13f7SAndroid Build Coastguard Worker fprintf(stderr, "error: could not write to file '%s'\n", filename);
180*03ce13f7SAndroid Build Coastguard Worker return false;
181*03ce13f7SAndroid Build Coastguard Worker }
182*03ce13f7SAndroid Build Coastguard Worker
183*03ce13f7SAndroid Build Coastguard Worker return true;
184*03ce13f7SAndroid Build Coastguard Worker }
185*03ce13f7SAndroid Build Coastguard Worker
186*03ce13f7SAndroid Build Coastguard Worker #endif // TOOLS_IO_H_
187