1 #include "nvram.h"
2 #include "retro_callbacks.h"
3 
4 #include <file/file_path.h>
5 #include <retro_endianness.h>
6 #include <retro_miscellaneous.h>
7 #include <streams/file_stream.h>
8 
9 static char NVRAM_FILENAME[] = "3DO.nvram";
10 
11 /*
12   At some point it'd be good to put the init code into a separate
13   module as part of the core emulator.
14  */
15 void
nvram_init(void * nvram_)16 nvram_init(void *nvram_)
17 {
18   struct NVRAM_Header *nvram_hdr = (struct NVRAM_Header*)nvram_;
19 
20   memset(nvram_,0,sizeof(struct NVRAM_Header));
21 
22   nvram_hdr->record_type         = 0x01;
23   nvram_hdr->sync_bytes[0]       = 'Z';
24   nvram_hdr->sync_bytes[1]       = 'Z';
25   nvram_hdr->sync_bytes[2]       = 'Z';
26   nvram_hdr->sync_bytes[3]       = 'Z';
27   nvram_hdr->sync_bytes[4]       = 'Z';
28   nvram_hdr->record_version      = 0x02;
29   nvram_hdr->label[0]            = 'N';
30   nvram_hdr->label[1]            = 'V';
31   nvram_hdr->label[2]            = 'R';
32   nvram_hdr->label[3]            = 'A';
33   nvram_hdr->label[4]            = 'M';
34   nvram_hdr->id                  = swap_if_little32(0xFFFFFFFF);
35   nvram_hdr->block_size          = swap_if_little32(0x00000001);
36   nvram_hdr->block_count         = swap_if_little32(0x00008000);
37   nvram_hdr->root_dir_id         = swap_if_little32(0xFFFFFFFE);
38   nvram_hdr->root_dir_blocks     = swap_if_little32(0x00000000);
39   nvram_hdr->root_dir_block_size = swap_if_little32(0x00000001);
40   nvram_hdr->last_root_dir_copy  = swap_if_little32(0x00000000);
41   nvram_hdr->root_dir_copies[0]  = swap_if_little32(0x00000084);
42   nvram_hdr->unknown_value0      = swap_if_little32(0x855A02B6);
43   nvram_hdr->unknown_value1      = swap_if_little32(0x00000098);
44   nvram_hdr->unknown_value2      = swap_if_little32(0x00000098);
45   nvram_hdr->unknown_value3      = swap_if_little32(0x00000014);
46   nvram_hdr->unknown_value4      = swap_if_little32(0x00000014);
47   nvram_hdr->unknown_value5      = swap_if_little32(0x7AA565BD);
48   nvram_hdr->unknown_value6      = swap_if_little32(0x00000084);
49   nvram_hdr->unknown_value7      = swap_if_little32(0x00000084);
50   nvram_hdr->blocks_remaining    = swap_if_little32(0x00007F68);
51   nvram_hdr->unknown_value8      = swap_if_little32(0x00000014);
52 }
53 
54 int
nvram_save(const void * nvram_,const size_t size_,const char * basepath_,const char * filename_)55 nvram_save(const void   *nvram_,
56            const size_t  size_,
57            const char   *basepath_,
58            const char   *filename_)
59 {
60   int rv;
61   char fullpath[PATH_MAX_LENGTH];
62   char fullpath_tmp[PATH_MAX_LENGTH];
63 
64   fill_pathname_join(fullpath,basepath_,filename_,sizeof(fullpath));
65   strncpy(fullpath_tmp,fullpath,sizeof(fullpath_tmp));
66   strncat(fullpath_tmp,".tmp",sizeof(fullpath_tmp) - strlen(fullpath_tmp) - 1);
67 
68   rv = filestream_write_file(fullpath_tmp,nvram_,size_);
69   if(rv == 0)
70     return -1;
71 
72   rv = filestream_rename(fullpath_tmp,fullpath);
73   if(rv != 0)
74     {
75       filestream_delete(fullpath);
76       rv = filestream_rename(fullpath_tmp,fullpath);
77     }
78 
79   return rv;
80 }
81 
82 int
nvram_load(void * nvram_,const size_t size_,const char * basepath_,const char * filename_)83 nvram_load(void         *nvram_,
84            const size_t  size_,
85            const char   *basepath_,
86            const char   *filename_)
87 {
88   RFILE *f;
89   int64_t rv;
90   char fullpath[PATH_MAX_LENGTH];
91 
92   fill_pathname_join(fullpath,basepath_,filename_,sizeof(fullpath));
93 
94   f = filestream_open(fullpath,
95                       RETRO_VFS_FILE_ACCESS_READ,
96                       RETRO_VFS_FILE_ACCESS_HINT_NONE);
97   if(f == NULL)
98     return -1;
99 
100   rv = filestream_read(f,nvram_,size_);
101 
102   filestream_close(f);
103 
104   return ((rv == size_) ? 0 : -1);
105 }
106 
107 /*
108   Ideally there would be a core specific directory available
109   regardless content is loaded but for now we'll save to the system
110   directory.
111  */
112 void
retro_nvram_save(const uint8_t * nvram_)113 retro_nvram_save(const uint8_t *nvram_)
114 {
115   int rv;
116   const char *basepath;
117   struct retro_variable var;
118 
119   rv = retro_environment_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY,&basepath);
120   if((rv == 0) || (basepath == NULL))
121     {
122       retro_log_printf_cb(RETRO_LOG_ERROR,
123                           "[Opera]: unable to save %s - system directory unavailable",
124                           NVRAM_FILENAME);
125       return;
126     }
127 
128   rv = nvram_save(nvram_,NVRAM_SIZE,basepath,NVRAM_FILENAME);
129   if(rv)
130     retro_log_printf_cb(RETRO_LOG_ERROR,
131                         "[Opera]: unknown error saving %s\n",
132                         NVRAM_FILENAME);
133 }
134 
135 void
retro_nvram_load(uint8_t * nvram_)136 retro_nvram_load(uint8_t *nvram_)
137 {
138   int rv;
139   const char *basepath;
140   struct retro_variable var;
141 
142   rv = retro_environment_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY,&basepath);
143   if((rv == 0) || (basepath == NULL))
144     {
145       retro_log_printf_cb(RETRO_LOG_ERROR,
146                           "[Opera]: unable to load %s - system directory unavailable",
147                           NVRAM_FILENAME);
148       return;
149     }
150 
151   rv = nvram_load(nvram_,NVRAM_SIZE,basepath,NVRAM_FILENAME);
152   if(rv)
153     retro_log_printf_cb(RETRO_LOG_ERROR,
154                         "[Opera]: unknown error loading %s\n",
155                         NVRAM_FILENAME);
156 }
157