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