file-serializer.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (c) 2023 Lain Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "dstr.h"
  17. #include "file-serializer.h"
  18. #include "platform.h"
  19. static size_t file_input_read(void *file, void *data, size_t size)
  20. {
  21. return fread(data, 1, size, file);
  22. }
  23. static int64_t file_input_seek(void *file, int64_t offset, enum serialize_seek_type seek_type)
  24. {
  25. int origin = SEEK_SET;
  26. switch (seek_type) {
  27. case SERIALIZE_SEEK_START:
  28. origin = SEEK_SET;
  29. break;
  30. case SERIALIZE_SEEK_CURRENT:
  31. origin = SEEK_CUR;
  32. break;
  33. case SERIALIZE_SEEK_END:
  34. origin = SEEK_END;
  35. break;
  36. }
  37. if (os_fseeki64(file, offset, origin) == -1)
  38. return -1;
  39. return os_ftelli64(file);
  40. }
  41. static int64_t file_input_get_pos(void *file)
  42. {
  43. return os_ftelli64(file);
  44. }
  45. bool file_input_serializer_init(struct serializer *s, const char *path)
  46. {
  47. s->data = os_fopen(path, "rb");
  48. if (!s->data)
  49. return false;
  50. s->read = file_input_read;
  51. s->write = NULL;
  52. s->seek = file_input_seek;
  53. s->get_pos = file_input_get_pos;
  54. return true;
  55. }
  56. void file_input_serializer_free(struct serializer *s)
  57. {
  58. if (s->data)
  59. fclose(s->data);
  60. }
  61. /* ------------------------------------------------------------------------- */
  62. struct file_output_data {
  63. FILE *file;
  64. char *temp_name;
  65. char *file_name;
  66. };
  67. static size_t file_output_write(void *sdata, const void *data, size_t size)
  68. {
  69. struct file_output_data *out = sdata;
  70. return fwrite(data, 1, size, out->file);
  71. }
  72. static int64_t file_output_seek(void *sdata, int64_t offset, enum serialize_seek_type seek_type)
  73. {
  74. struct file_output_data *out = sdata;
  75. int origin = SEEK_SET;
  76. switch (seek_type) {
  77. case SERIALIZE_SEEK_START:
  78. origin = SEEK_SET;
  79. break;
  80. case SERIALIZE_SEEK_CURRENT:
  81. origin = SEEK_CUR;
  82. break;
  83. case SERIALIZE_SEEK_END:
  84. origin = SEEK_END;
  85. break;
  86. }
  87. if (os_fseeki64(out->file, offset, origin) == -1)
  88. return -1;
  89. return os_ftelli64(out->file);
  90. }
  91. static int64_t file_output_get_pos(void *sdata)
  92. {
  93. struct file_output_data *out = sdata;
  94. return os_ftelli64(out->file);
  95. }
  96. bool file_output_serializer_init(struct serializer *s, const char *path)
  97. {
  98. FILE *file = os_fopen(path, "wb");
  99. struct file_output_data *out;
  100. if (!file)
  101. return false;
  102. out = bzalloc(sizeof(*out));
  103. out->file = file;
  104. s->data = out;
  105. s->read = NULL;
  106. s->write = file_output_write;
  107. s->seek = file_output_seek;
  108. s->get_pos = file_output_get_pos;
  109. return true;
  110. }
  111. bool file_output_serializer_init_safe(struct serializer *s, const char *path, const char *temp_ext)
  112. {
  113. struct dstr temp_name = {0};
  114. struct file_output_data *out;
  115. FILE *file;
  116. if (!temp_ext || !*temp_ext)
  117. return false;
  118. dstr_copy(&temp_name, path);
  119. if (*temp_ext != '.')
  120. dstr_cat_ch(&temp_name, '.');
  121. dstr_cat(&temp_name, temp_ext);
  122. file = os_fopen(temp_name.array, "wb");
  123. if (!file) {
  124. dstr_free(&temp_name);
  125. return false;
  126. }
  127. out = bzalloc(sizeof(*out));
  128. out->file_name = bstrdup(path);
  129. out->temp_name = temp_name.array;
  130. out->file = file;
  131. s->data = out;
  132. s->read = NULL;
  133. s->write = file_output_write;
  134. s->seek = file_output_seek;
  135. s->get_pos = file_output_get_pos;
  136. return true;
  137. }
  138. void file_output_serializer_free(struct serializer *s)
  139. {
  140. struct file_output_data *out = s->data;
  141. if (out) {
  142. fclose(out->file);
  143. if (out->temp_name) {
  144. os_unlink(out->file_name);
  145. os_rename(out->temp_name, out->file_name);
  146. }
  147. bfree(out->file_name);
  148. bfree(out->temp_name);
  149. bfree(out);
  150. }
  151. }