OSDN Git Service

unicode support
[unagi/old-svn-converted.git] / client / trunk / header.c
1 /*
2 famicom ROM cartridge utility - unagi
3 iNES header/buffer control
4 */
5 #include <assert.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include "memory_manage.h"
10 #include "type.h"
11 #include "file.h"
12 #include "crc32.h"
13 #include "config.h"
14 #include "widget.h"
15 #include "header.h"
16
17 enum{
18         NES_HEADER_SIZE = 0x10,
19         PROGRAM_ROM_MIN = 0x4000,
20         CHARCTER_ROM_MIN = 0x2000
21 };
22 static const uint8_t NES_HEADER_INIT[NES_HEADER_SIZE] = {
23         'N', 'E', 'S', 0x1a, 0, 0, 0, 0,
24         0, 0, 0, 0, 0, 0, 0, 0
25 };
26
27 #ifndef HEADEROUT
28 static 
29 #endif
30 void nesheader_set(const struct romimage *r, uint8_t *header)
31 {
32         memcpy(header, NES_HEADER_INIT, NES_HEADER_SIZE);
33         header[4] = r->cpu_rom.size / PROGRAM_ROM_MIN;
34         header[5] = r->ppu_rom.size / CHARCTER_ROM_MIN;
35         if(r->mirror == MIRROR_VERTICAL){
36                 header[6] |= 0x01;
37         }
38         if((r->cpu_ram.size != 0) || (r->backupram == true)){
39                 header[6] |= 0x02;
40         }
41         //4 screen ¤Ï̵»ë
42         header[6] |= (r->mappernum & 0x0f) << 4;
43         header[7] |= r->mappernum & 0xf0;
44 }
45
46 #ifndef HEADEROUT
47 /*
48 returnÃÍ: error count
49 */
50 static int mirroring_fix(const struct textcontrol *l, struct memory *m, long min)
51 {
52         long mirror_size = m->size / 2;
53         while(mirror_size >= min){
54                 const uint8_t *halfbuf;
55                 halfbuf = m->data;
56                 halfbuf += mirror_size;
57                 if(memcmp(m->data, halfbuf, mirror_size) != 0){
58                         const long ret = mirror_size * 2;
59                         if(m->size != ret){
60                                 l->append(l->object, wgT("mirroring %s ROM fixed\n"), m->name);
61                                 m->size = ret;
62                         }
63                         return 0;
64                 }
65                 mirror_size /= 2;
66         }
67         
68         uint8_t *ffdata;
69         int ret = 0;
70         ffdata = Malloc(min);
71         memset(ffdata, 0xff, min);
72         if(memcmp(ffdata, m->data, min) == 0){
73                 l->append(l->object, wgT("error: data is all 0xff\n"));
74                 ret = 1;
75         }else if(m->size != min){
76                 l->append(l->object, wgT("mirroring %s ROM fixed\n"), m->name);
77                 m->size = min;
78         }
79         Free(ffdata);
80         
81         return ret;
82 }
83
84 //hash ¤Ï sha1 ¤Ë¤·¤¿¤¤¤¬Â¾¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤¢¤ï¤»¤Æ crc32 ¤Ë¤·¤È¤¯
85 static void rominfo_print(const struct textcontrol *l, const struct memory *m)
86 {
87         if(m->size != 0){
88                 const uint32_t crc = crc32_get(m->data, m->size);
89                 l->append(l->object, wgT("%s ROM: size 0x%06x, crc32 0x%08x\n"), m->name, m->size, (const int) crc);
90         }else{
91                 l->append(l->object, wgT("%s RAM\n"), m->name);
92         }
93 }
94
95 void nesfile_create(const struct textcontrol *l, struct romimage *r, const wgChar *romfilename)
96 {
97         int error = 0;
98         //RAM adapter bios size 0x2000 ¤ÏÊѹ¹¤·¤Ê¤¤
99         if(r->cpu_rom.size >= PROGRAM_ROM_MIN){
100                 error += mirroring_fix(l, &(r->cpu_rom), PROGRAM_ROM_MIN);
101         }
102         if(r->ppu_rom.size != 0){
103                 error += mirroring_fix(l, &(r->ppu_rom), CHARCTER_ROM_MIN);
104         }
105         if((DEBUG == 0) && (error != 0)){
106                 return;
107         }
108         //½¤ÀµºÑ¤ß ROM ¾ðÊóɽ¼¨
109         l->append(l->object, wgT("%s, mapper %d\n"), romfilename, (int) r->mappernum);
110         rominfo_print(l, &(r->cpu_rom));
111         rominfo_print(l, &(r->ppu_rom));
112
113         FILE *f;
114         uint8_t header[NES_HEADER_SIZE];
115         nesheader_set(r, header);
116 #ifdef _UNICODE
117         f = _wfopen(romfilename, L"wb");
118 #else
119         f = fopen(romfilename, "wb");
120 #endif
121         fseek(f, 0, SEEK_SET);
122         //RAM adapter bios ¤Ë¤Ï NES ¥Ø¥Ã¥À¤òºî¤é¤Ê¤¤
123         if(r->cpu_rom.size >= PROGRAM_ROM_MIN){ 
124                 fwrite(header, sizeof(uint8_t), NES_HEADER_SIZE, f);
125         }
126         fwrite(r->cpu_rom.data, sizeof(uint8_t), r->cpu_rom.size, f);
127         if(r->ppu_rom.size != 0){
128                 fwrite(r->ppu_rom.data, sizeof(uint8_t), r->ppu_rom.size, f);
129         }
130         fclose(f);
131 }
132
133 static inline void memory_malloc(struct memory *m)
134 {
135         m->data = NULL;
136         if(m->size != 0){
137                 m->data = Malloc(m->size);
138         }
139 }
140
141 bool nesbuffer_malloc(struct romimage *r, int mode)
142 {
143         switch(mode){
144         case MODE_ROM_DUMP:
145                 memory_malloc(&(r->cpu_rom));
146                 memory_malloc(&(r->ppu_rom));
147                 break;
148         case MODE_RAM_READ:
149                 memory_malloc(&(r->cpu_ram));
150                 break;
151         }
152         return true;
153 }
154
155 static inline void memory_free(struct memory *m)
156 {
157         if(m->data != NULL){
158                 Free(m->data);
159                 m->data = NULL;
160         }
161 }
162 void nesbuffer_free(struct romimage *r, int mode)
163 {
164         memory_free(&(r->cpu_rom));
165         memory_free(&(r->ppu_rom));
166         if(mode == MODE_RAM_READ){
167                 memory_free(&(r->cpu_ram));
168         }
169 }
170
171 void backupram_create(const struct memory *r, const wgChar *ramfilename)
172 {
173         buf_save(r->data, ramfilename, r->size);
174 }
175
176 /*
177 memory size ¤Ï 2¾è¤µ¤ì¤Æ¤¤¤¯Ãͤ¬Àµ¾ïÃÍ.
178 ¤¿¤À¤·¡¢region ¤ÎºÇ¾®Ãͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï test ÍѤȤ·¤ÆÀµ¾ï¤Ë¤¹¤ë
179 */
180 int memorysize_check(const long size, int region)
181 {
182         long min = 0;
183         switch(region){
184         case MEMORY_AREA_CPU_ROM:
185                 min = PROGRAM_ROM_MIN;
186                 break;
187         case MEMORY_AREA_CPU_RAM:
188                 min = 0x800; //¤¤¤Þ¤Î¤È¤³¤í. taito ·Ï¤Ï¤â¤Ã¤È¾®¤µ¤¤¤è¤¦¤Êµ¤¤¬¤¹¤ë
189                 break;
190         case MEMORY_AREA_PPU:
191                 min = CHARCTER_ROM_MIN;
192                 break;
193         default:
194                 assert(0);
195         }
196         if(size <= min){
197                 return OK;
198         }
199         switch(size){
200         case 0x004000: //128K bit
201         case 0x008000: //256K
202         case 0x010000: //512K
203         case 0x020000: //1M
204         case 0x040000: //2M
205         case 0x080000: //4M
206         case 0x100000: //8M
207                 return OK;
208         }
209         return NG;
210 }
211
212 /*
213 romimage ¤¬ bank ¤ÎÄêµÁÃͤè¤ê¾®¤µ¤¤¾ì¹ç¤Ï romarea ¤ÎËöÈø¤ËÄ¥¤ë¡£ 
214 Ʊ¤¸¥Ç¡¼¥¿¤ò memcpy ¤·¤¿¤Û¤¦¤¬°ÂÁ´¤À¤¬¡¢¤È¤ê¤¢¤¨¤º¤Ç¡£
215 */
216 static void nesfile_datapointer_set(const uint8_t *buf, struct memory *m, long size)
217 {
218         uint8_t *data;
219         assert((size % CHARCTER_ROM_MIN) == 0);
220         assert((m->size % CHARCTER_ROM_MIN) == 0);
221         data = Malloc(size);
222         m->data = data;
223         if(size < m->size){
224                 long fillsize = m->size - size;
225                 assert(fillsize >= 0); //fillsize is minus
226                 memset(data, 0xff, fillsize); //ROM ¤Î̤»ÈÍÑÎΰè¤Ï 0xff ¤¬´ðËÜ
227                 data += fillsize;
228                 size -= fillsize;
229         }
230         memcpy(data, buf, size);
231 }
232
233 //flashmemory device capacity check ¤¬È´¤±¤Æ¤ë¤±¤É¤É¤³¤Ç¤ä¤ë¤«Ì¤Äê
234 bool nesfile_load(const struct textcontrol *l, const wgChar *file, struct romimage *r)
235 {
236         int imagesize;
237         uint8_t *buf;
238         
239         buf = buf_load_full(file, &imagesize);
240         if(buf == NULL || imagesize < (NES_HEADER_SIZE + PROGRAM_ROM_MIN)){
241 //              printf("%s ROM image open error\n", errorprefix);
242                 return false;
243         }
244         //nes header check
245         if(memcmp(buf, NES_HEADER_INIT, 4) != 0){
246                 l->append(l->object, wgT("NES header identify error\n"));
247                 Free(buf);
248                 return false;
249         }
250         //vram mirroring set
251         if((buf[6] & 1) == 0){
252                 r->mirror = MIRROR_HORIZONAL;
253         }else{
254                 r->mirror = MIRROR_VERTICAL;
255         }
256         //mapper number check
257         {
258                 long mapper = (buf[6] >> 4) & 0x0f;
259                 mapper |= buf[7] & 0xf0;
260                 r->mappernum = mapper;
261         }
262         //NES/CPU/PPU imagesize check
263         long cpusize, ppusize;
264         {
265                 long offset = NES_HEADER_SIZE;
266                 //CPU
267                 cpusize = ((long) buf[4]) * PROGRAM_ROM_MIN;
268                 offset += cpusize;
269                 r->cpu_rom.size = cpusize;
270                 //PPU
271                 ppusize = ((long) buf[5]) * CHARCTER_ROM_MIN;
272                 offset += ppusize;
273                 r->ppu_rom.size = ppusize;
274                 //NESfilesize
275                 if(offset != imagesize){
276                         l->append(l->object, wgT("NES header filesize error\n"));
277                         Free(buf);
278                         return false;
279                 }
280         }
281         /*
282         image pointer set/ memcpy
283         */
284         {
285                 uint8_t *d;
286                 d = buf;
287                 d += NES_HEADER_SIZE;
288                 nesfile_datapointer_set(d, &r->cpu_rom, cpusize);
289                 d += cpusize;
290                 if(ppusize != 0){
291                         nesfile_datapointer_set(d, &r->ppu_rom, ppusize);
292                 }else{
293                         r->ppu_rom.data = NULL;
294                         r->ppu_rom.size = 0;
295                 }
296         }
297
298         Free(buf);
299         return true;
300 }
301 #endif