// Copyright (c) 2016 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef TOOLS_IO_H_ #define TOOLS_IO_H_ #include #include #include #include #if defined(SPIRV_WINDOWS) #include #include #define SET_STDIN_TO_BINARY_MODE() _setmode(_fileno(stdin), O_BINARY); #define SET_STDIN_TO_TEXT_MODE() _setmode(_fileno(stdin), O_TEXT); #else #define SET_STDIN_TO_BINARY_MODE() #define SET_STDIN_TO_TEXT_MODE() #endif // Appends the contents of the |file| to |data|, assuming each element in the // file is of type |T|. template void ReadFile(FILE* file, std::vector* data) { if (file == nullptr) return; const int buf_size = 1024; T buf[buf_size]; while (size_t len = fread(buf, sizeof(T), buf_size, file)) { data->insert(data->end(), buf, buf + len); } } // Returns true if |file| has encountered an error opening the file or reading // the file as a series of element of type |T|. If there was an error, writes an // error message to standard error. template bool WasFileCorrectlyRead(FILE* file, const char* filename) { if (file == nullptr) { fprintf(stderr, "error: file does not exist '%s'\n", filename); return false; } if (ftell(file) == -1L) { if (ferror(file)) { fprintf(stderr, "error: error reading file '%s'\n", filename); return false; } } else { if (sizeof(T) != 1 && (ftell(file) % sizeof(T))) { fprintf( stderr, "error: file size should be a multiple of %zd; file '%s' corrupt\n", sizeof(T), filename); return false; } } return true; } // Appends the contents of the file named |filename| to |data|, assuming // each element in the file is of type |T|. The file is opened as a binary file // If |filename| is nullptr or "-", reads from the standard input, but // reopened as a binary file. If any error occurs, writes error messages to // standard error and returns false. template bool ReadBinaryFile(const char* filename, std::vector* data) { const bool use_file = filename && strcmp("-", filename); FILE* fp = nullptr; if (use_file) { fp = fopen(filename, "rb"); } else { SET_STDIN_TO_BINARY_MODE(); fp = stdin; } ReadFile(fp, data); bool succeeded = WasFileCorrectlyRead(fp, filename); if (use_file && fp) fclose(fp); return succeeded; } // Appends the contents of the file named |filename| to |data|, assuming // each element in the file is of type |T|. The file is opened as a text file // If |filename| is nullptr or "-", reads from the standard input, but // reopened as a text file. If any error occurs, writes error messages to // standard error and returns false. template bool ReadTextFile(const char* filename, std::vector* data) { const bool use_file = filename && strcmp("-", filename); FILE* fp = nullptr; if (use_file) { fp = fopen(filename, "r"); } else { SET_STDIN_TO_TEXT_MODE(); fp = stdin; } ReadFile(fp, data); bool succeeded = WasFileCorrectlyRead(fp, filename); if (use_file && fp) fclose(fp); return succeeded; } // Writes the given |data| into the file named as |filename| using the given // |mode|, assuming |data| is an array of |count| elements of type |T|. If // |filename| is nullptr or "-", writes to standard output. If any error occurs, // returns false and outputs error message to standard error. template bool WriteFile(const char* filename, const char* mode, const T* data, size_t count) { const bool use_stdout = !filename || (filename[0] == '-' && filename[1] == '\0'); if (FILE* fp = (use_stdout ? stdout : fopen(filename, mode))) { size_t written = fwrite(data, sizeof(T), count, fp); if (count != written) { fprintf(stderr, "error: could not write to file '%s'\n", filename); if (!use_stdout) fclose(fp); return false; } if (!use_stdout) fclose(fp); } else { fprintf(stderr, "error: could not open file '%s'\n", filename); return false; } return true; } #endif // TOOLS_IO_H_