|
@@ -0,0 +1,167 @@
|
|
|
|
|
+#ifndef FILE_H
|
|
|
|
|
+#define FILE_H
|
|
|
|
|
+
|
|
|
|
|
+#include <stddef.h>
|
|
|
|
|
+#include <stdint.h>
|
|
|
|
|
+
|
|
|
|
|
+#define CONCAT(a, b) CONCAT_INNER(a, b)
|
|
|
|
|
+#define CONCAT_INNER(a, b) a ## b
|
|
|
|
|
+
|
|
|
|
|
+#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__)
|
|
|
|
|
+
|
|
|
|
|
+enum file_err {
|
|
|
|
|
+ FILE_ERR_OK,
|
|
|
|
|
+ FILE_ERR_FAIL_OPEN,
|
|
|
|
|
+ FILE_ERR_FAIL_SEEK,
|
|
|
|
|
+ FILE_ERR_FAIL_READ,
|
|
|
|
|
+ FILE_ERR_FAIL_WRITE,
|
|
|
|
|
+ FILE_ERR_FAIL_CALLOC,
|
|
|
|
|
+ FILE_ERR_FAIL_CLOSE,
|
|
|
|
|
+ FILE_ERR_FILE_EMPTY,
|
|
|
|
|
+ FILE_ERR_FAIL_WROTE_MORE,
|
|
|
|
|
+ FILE_ERR_EMPTY
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+uint8_t *file_read_all(const char *filepath, size_t *ret_size,
|
|
|
|
|
+ enum file_err *ret_err);
|
|
|
|
|
+void file_save(const char *filepath, const char *str, size_t str_size,
|
|
|
|
|
+ enum file_err *ret_err);
|
|
|
|
|
+
|
|
|
|
|
+void file_err_set(enum file_err *err, enum file_err err_);
|
|
|
|
|
+const char *file_err_to_cstr(enum file_err err);
|
|
|
|
|
+
|
|
|
|
|
+#if defined(BMP_IMP) || defined(IMP)
|
|
|
|
|
+
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
+#include <fcntl.h>
|
|
|
|
|
+#include <sys/stat.h>
|
|
|
|
|
+
|
|
|
|
|
+uint8_t *
|
|
|
|
|
+file_read_all(const char *filepath, size_t *ret_size, enum file_err *ret_err)
|
|
|
|
|
+{
|
|
|
|
|
+ int32_t fd = -1;
|
|
|
|
|
+ off_t file_size = -1;
|
|
|
|
|
+ size_t buf_size = 0;
|
|
|
|
|
+ uint8_t *buf = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ fd = open(filepath, O_RDONLY);
|
|
|
|
|
+ if ( fd < 0 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_OPEN);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ file_size = lseek(fd, 0, SEEK_END);
|
|
|
|
|
+ if ( file_size < 0 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_SEEK);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ lseek(fd, 0, SEEK_SET);
|
|
|
|
|
+
|
|
|
|
|
+ if ( file_size == 0 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_EMPTY);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ buf_size = ((size_t)file_size) + 1;
|
|
|
|
|
+ buf = calloc(buf_size, sizeof(uint8_t));
|
|
|
|
|
+ if ( buf == NULL ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_CALLOC);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ ssize_t rd = read(fd, buf, (size_t)file_size);
|
|
|
|
|
+ if ( rd < 0 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_READ);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ free(buf);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ( rd == 0 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FILE_EMPTY);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ free(buf);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( close(fd) != 0 ) {
|
|
|
|
|
+ /* It should be possible to handle EIO */
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_CLOSE);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( ret_size != NULL ) {
|
|
|
|
|
+ *ret_size = buf_size;
|
|
|
|
|
+ }
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_OK);
|
|
|
|
|
+ return buf;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void
|
|
|
|
|
+file_save(const char *filepath, const char *str, size_t str_size,
|
|
|
|
|
+ enum file_err *ret_err)
|
|
|
|
|
+{
|
|
|
|
|
+ ssize_t wrote = -1;
|
|
|
|
|
+ int32_t fd = open(filepath,
|
|
|
|
|
+ O_WRONLY | O_CREAT | O_TRUNC,
|
|
|
|
|
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
|
|
|
+ if ( fd < 0 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_OPEN);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ wrote = write(fd, str, str_size);
|
|
|
|
|
+ if ( wrote == -1 ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_WRITE);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( ((size_t) wrote) != str_size ) {
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_WROTE_MORE);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( close(fd) != 0 ) {
|
|
|
|
|
+ /* It should be possible to handle EIO */
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_FAIL_CLOSE);
|
|
|
|
|
+ close(fd);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ file_err_set(ret_err, FILE_ERR_OK);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void
|
|
|
|
|
+file_err_set(enum file_err *err, enum file_err err_)
|
|
|
|
|
+{
|
|
|
|
|
+ if ( err != NULL ) {
|
|
|
|
|
+ *err = err_;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const char *
|
|
|
|
|
+file_err_to_cstr(enum file_err err)
|
|
|
|
|
+{
|
|
|
|
|
+ switch ( err ) {
|
|
|
|
|
+ case FILE_ERR_OK: return "FILE_ERR_OK"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_OPEN: return "FILE_ERR_FAIL_OPEN"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_SEEK: return "FILE_ERR_FAIL_SEEK"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_READ: return "FILE_ERR_FAIL_READ"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_WRITE: return "FILE_ERR_FAIL_WRITE"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_CALLOC: return "FILE_ERR_FAIL_CALLOC"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_CLOSE: return "FILE_ERR_FAIL_CLOSE"; break;
|
|
|
|
|
+ case FILE_ERR_FILE_EMPTY: return "FILE_ERR_FILE_EMPTY"; break;
|
|
|
|
|
+ case FILE_ERR_FAIL_WROTE_MORE: return "FILE_ERR_FAIL_WROTE_MORE"; break;
|
|
|
|
|
+ case FILE_ERR_EMPTY: return "FILE_ERR_EMPTY"; break;
|
|
|
|
|
+ }
|
|
|
|
|
+ return "FILE ERR INVALID";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#endif
|
|
|
|
|
+#endif
|