From ecd66f59c2b00978589457fb296d05d4ef694c12 Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Thu, 2 Feb 2017 22:27:51 +0100 Subject: [PATCH] Added different scaling methods based on screenmode - All Picasso modes and the menu use linear scaling, all other modes (PAL/NTSC) use nearest neighbor. #47 - Code cleanup --- .gitignore | 3 +- src/drawing.cpp | 15 +- src/main.cpp | 2 - src/osdep/gui/main_window.cpp | 3 +- src/osdep/keyboard.cpp | 29 +- src/osdep/pandora.cpp | 28 +- src/osdep/pandora_gfx.cpp | 90 +- src/p96_blit.cpp | 330 +- src/sinctable.cpp | 1262 +++---- src/uaelib.cpp | 864 ++--- src/zfile.cpp | 6448 ++++++++++++++++----------------- 11 files changed, 4469 insertions(+), 4605 deletions(-) diff --git a/.gitignore b/.gitignore index 34a8ec69..01588760 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,5 @@ VisualGDB/VisualGDB/Release/Amiberry-sdl2 *.npa00-cfdc2249 *.a *.npa00-f5145647 -VisualGDB/VisualGDB/Debug/Amiberry-sdl2 \ No newline at end of file +VisualGDB/VisualGDB/Debug/Amiberry-sdl2 +*.npa00-25509379 \ No newline at end of file diff --git a/src/drawing.cpp b/src/drawing.cpp index a7197e4a..60144ecf 100644 --- a/src/drawing.cpp +++ b/src/drawing.cpp @@ -34,7 +34,7 @@ #include "options.h" #include "threaddep/thread.h" #include "uae.h" -#include "memory.h" +#include "include/memory.h" #include "custom.h" #include "newcpu.h" #include "xwin.h" @@ -334,7 +334,7 @@ static void pfield_do_linetoscr_0_AGA(int start, int stop) STATIC_INLINE xcolnr getbgc(bool blank) { - return (blank || colors_for_drawing.borderblank) ? 0 : colors_for_drawing.acolors[0]; + return (blank || colors_for_drawing.extra) ? 0 : colors_for_drawing.acolors[0]; } static void pfield_do_fill_line_0_640(int start, int stop) @@ -403,7 +403,7 @@ static void pfield_init_linetoscr() if (playfield_end > visible_right_border) playfield_end = visible_right_border; - if (dp_for_drawing->bordersprite_seen && !colors_for_drawing.borderblank && dip_for_drawing->nr_sprites) + if (dp_for_drawing->bordersprite_seen && !colors_for_drawing.extra && dip_for_drawing->nr_sprites) { int min = visible_right_border, max = visible_left_border, i; for (i = 0; i < dip_for_drawing->nr_sprites; i++) @@ -2006,8 +2006,7 @@ static void adjust_drawing_colors(int ctable, int need_full) memcpy(colors_for_drawing.acolors, curr_color_tables[ctable].acolors, sizeof colors_for_drawing.acolors); - colors_for_drawing.borderblank = curr_color_tables[ctable].borderblank; - colors_for_drawing.bordersprite = curr_color_tables[ctable].bordersprite; + colors_for_drawing.extra = curr_color_tables[ctable].extra; color_match_type = color_match_acolors; } drawing_color_matches = ctable; @@ -2072,8 +2071,8 @@ STATIC_INLINE void do_color_changes(line_draw_func worker_border, line_draw_func { if (regno == 0 && (value & COLOR_CHANGE_BRDBLANK)) { - colors_for_drawing.borderblank = (value & 1) != 0; - colors_for_drawing.bordersprite = (value & 3) == 2; + colors_for_drawing.extra = (value & 1) != 0; + colors_for_drawing.extra = (value & 3) == 2; } else { @@ -2147,7 +2146,7 @@ static void pfield_draw_line(int lineno, int gfx_ypos) adjust_drawing_colors(dp_for_drawing->ctable, 0); /* this makes things complex.. */ - if (dp_for_drawing->bordersprite_seen && !colors_for_drawing.borderblank && dip_for_drawing->nr_sprites) + if (dp_for_drawing->bordersprite_seen && !colors_for_drawing.extra && dip_for_drawing->nr_sprites) { dosprites = true; pfield_expand_dp_bplcon(); diff --git a/src/main.cpp b/src/main.cpp index aa626da4..d19e2cf0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -666,8 +666,6 @@ static int real_main2 (int argc, TCHAR **argv) renderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); check_error_sdl(renderer == nullptr, "Unable to create a renderer"); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother. - keyboard_settrans(); if (restart_config[0]) { diff --git a/src/osdep/gui/main_window.cpp b/src/osdep/gui/main_window.cpp index c5908cbd..6b106566 100644 --- a/src/osdep/gui/main_window.cpp +++ b/src/osdep/gui/main_window.cpp @@ -139,7 +139,6 @@ void RegisterRefreshFunc(void (*func)()) refreshFuncAfterDraw = func; } - namespace sdl { void gui_init() @@ -148,6 +147,8 @@ namespace sdl // Create new screen for GUI //------------------------------------------------- + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother (linear scaling). + gui_screen = SDL_CreateRGBSurface(0, GUI_WIDTH, GUI_HEIGHT, 32, 0, 0, 0, 0); check_error_sdl(gui_screen == nullptr, "Unable to create a surface"); diff --git a/src/osdep/keyboard.cpp b/src/osdep/keyboard.cpp index d2bf1543..d8f4c639 100644 --- a/src/osdep/keyboard.cpp +++ b/src/osdep/keyboard.cpp @@ -355,33 +355,8 @@ static int *kbmaps[] = { kb_none, kb_none, kb_none, kb_none, kb_none, void keyboard_settrans () { -// char vid_drv_name[32]; -// // get display type... -// SDL_VideoDriverName(vid_drv_name, sizeof(vid_drv_name)); -// if (strcmp(vid_drv_name, "x11") == 0) -// { -//#ifdef DEBUG -// printf("Will use keycode from x11 mapping.\n"); -//#endif -// keyboard_type = KEYCODE_X11; -// inputdevice_setkeytranslation (keytrans_x11, kbmaps); -// } -// else if (strcmp(vid_drv_name, "fbcon") == 0) -// { -//#ifdef DEBUG -// printf("Will use keycode from fbcon mapping.\n"); -//#endif -// keyboard_type = KEYCODE_FBCON; -// inputdevice_setkeytranslation (keytrans_fbcon, kbmaps); -// } -// else -// { -//#ifdef DEBUG -// printf("Unknown keycode to use, will use keysym\n"); -//#endif - keyboard_type = KEYCODE_UNK; - inputdevice_setkeytranslation (keytrans, kbmaps); -// } + keyboard_type = KEYCODE_UNK; + inputdevice_setkeytranslation (keytrans, kbmaps); } int translate_pandora_keys(int symbol, int *modifier) diff --git a/src/osdep/pandora.cpp b/src/osdep/pandora.cpp index a55f04f7..05deb1d0 100644 --- a/src/osdep/pandora.cpp +++ b/src/osdep/pandora.cpp @@ -848,15 +848,6 @@ int handle_msgpump() inputdevice_do_keyboard(AK_CTRL, 1); break; - // case VK_L: // Left shoulder button - // case VK_R: // Right shoulder button - // if(currprefs.input_tablet > TABLET_OFF) - // { - // // Holding left or right shoulder button -> stylus does right mousebutton - // doStylusRightClick = 1; - // } - // Fall through... - default: // if (currprefs.pandora_customControls) // { @@ -889,10 +880,7 @@ int handle_msgpump() // } // else // { - if (keyboard_type == KEYCODE_UNK) - inputdevice_translatekeycode(0, rEvent.key.keysym.sym, 1); - else - inputdevice_translatekeycode(0, rEvent.key.keysym.scancode, 1); + inputdevice_translatekeycode(0, rEvent.key.keysym.sym, 1); // } break; } @@ -928,15 +916,6 @@ int handle_msgpump() inputdevice_do_keyboard(AK_CTRL, 0); break; - // case VK_L: // Left shoulder button - // case VK_R: // Right shoulder button - // if(currprefs.input_tablet > TABLET_OFF) - // { - // // Release left or right shoulder button -> stylus does left mousebutton - // doStylusRightClick = 0; - // } - // Fall through... - default: // if (currprefs.pandora_customControls) // { @@ -965,10 +944,7 @@ int handle_msgpump() // } // else // { - if (keyboard_type == KEYCODE_UNK) - inputdevice_translatekeycode(0, rEvent.key.keysym.sym, 0); - else - inputdevice_translatekeycode(0, rEvent.key.keysym.scancode, 0); + inputdevice_translatekeycode(0, rEvent.key.keysym.sym, 0); // } break; } diff --git a/src/osdep/pandora_gfx.cpp b/src/osdep/pandora_gfx.cpp index c75bc410..fe2e83e9 100644 --- a/src/osdep/pandora_gfx.cpp +++ b/src/osdep/pandora_gfx.cpp @@ -50,59 +50,13 @@ int graphics_setup(void) return 1; } -#ifdef WITH_LOGGING - -SDL_Surface *liveInfo = NULL; -TTF_Font *liveFont = NULL; -int liveInfoCounter = 0; -void ShowLiveInfo(char *msg) -{ - if(liveFont == NULL) - { - TTF_Init(); - liveFont = TTF_OpenFont("data/FreeSans.ttf", 12); - } - if(liveInfo != NULL) - SDL_FreeSurface(liveInfo); - SDL_Color col; - col.r = 0xbf; - col.g = 0xbf; - col.b = 0xbf; - liveInfo = TTF_RenderText_Solid(liveFont, msg, col); - liveInfoCounter = 50 * 5; -} - -void RefreshLiveInfo() -{ - if(liveInfoCounter > 0) - { - SDL_Rect dst, src; - - dst.x = 0; - dst.y = 2; - src.w = liveInfo->w; - src.h = liveInfo->h; - src.x = 0; - src.y = 0; - SDL_BlitSurface(liveInfo, &src, prSDLScreen, &dst); - liveInfoCounter--; - if(liveInfoCounter == 0) - { - SDL_FreeSurface(liveInfo); - liveInfo = NULL; - } - } -} - -#endif - void InitAmigaVidMode(struct uae_prefs* p) { /* Initialize structure for Amiga video modes */ gfxvidinfo.pixbytes = 2; gfxvidinfo.bufmem = static_cast(screen->pixels); gfxvidinfo.outwidth = screen->w ? screen->w : 320; //p->gfx_size.width; - gfxvidinfo.outheight = screen->h ? screen->h : 240; //p->gfx_size.height; + gfxvidinfo.outheight = screen->h ? screen->h : 256; //p->gfx_size.height; gfxvidinfo.rowbytes = screen->pitch; } @@ -137,6 +91,7 @@ static void open_screen(struct uae_prefs* p) p->gfx_resolution = p->gfx_size.width > 600 ? 1 : 0; width = p->gfx_size.width; height = p->gfx_size.height; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); } graphics_subshutdown(); @@ -251,32 +206,6 @@ void flush_screen() RefreshLiveInfo(); #endif - // unsigned long start = read_processor_time(); - // if(current_vsync_frame == 0) - // { - // // Old style for vsync and idle time calc - // if(start < next_synctime && next_synctime - start > time_per_frame - 1000) - // usleep((next_synctime - start) - 750); - // ioctl(fbdev, OMAPFB_WAITFORVSYNC, ¤t_vsync_frame); - // } - // else - // { - // // New style for vsync and idle time calc - // int wait_till = current_vsync_frame; - // do - // { - // ioctl(fbdev, OMAPFB_WAITFORVSYNC_FRAME, ¤t_vsync_frame); - // } - // while (wait_till >= current_vsync_frame); - // - // if(wait_till + 1 != current_vsync_frame) - // { - // // We missed a vsync... - // next_synctime = 0; - // } - // current_vsync_frame += currprefs.gfx_framerate; - // } - // Update the texture from the surface SDL_UpdateTexture(texture, nullptr, screen->pixels, screen->pitch); // Copy the texture on the renderer @@ -284,21 +213,6 @@ void flush_screen() // Update the window surface (show the renderer) SDL_RenderPresent(renderer); - // last_synctime = read_processor_time(); - - // if(!screen_is_picasso) - // gfxvidinfo.bufmem = (uae_u8 *)screen->pixels; - - // if(last_synctime - next_synctime > time_per_frame * (1 + currprefs.gfx_framerate) - 1000 || next_synctime < start) - // adjust_idletime(0); - // else - // adjust_idletime(next_synctime - start); - // - // if (last_synctime - next_synctime > time_per_frame - 5000) - // next_synctime = last_synctime + time_per_frame * (1 + currprefs.gfx_framerate); - // else - // next_synctime = next_synctime + time_per_frame * (1 + currprefs.gfx_framerate); - init_row_map(); } diff --git a/src/p96_blit.cpp b/src/p96_blit.cpp index 2da308a6..82ee8de8 100644 --- a/src/p96_blit.cpp +++ b/src/p96_blit.cpp @@ -1,165 +1,165 @@ - -#if BLT_SIZE == 3 -static void NOINLINE BLT_NAME (unsigned int w, unsigned int h, uae_u8 *src, uae_u8 *dst, int srcpitch, int dstpitch) -{ - uae_u8 *src2 = src; - uae_u8 *dst2 = dst; - uae_u32 *src2_32 = (uae_u32*)src; - uae_u32 *dst2_32 = (uae_u32*)dst; - unsigned int y, x, ww, xxd; -#ifdef BLT_TEMP - uae_u32 tmp; -#endif - w *= BLT_SIZE; - ww = w / 4; - xxd = w - (ww * 4); - for(y = 0; y < h; y++) - { - uae_u8 *src_8; - uae_u8 *dst_8; - uae_u32 *src_32 = (uae_u32*)src2; - uae_u32 *dst_32 = (uae_u32*)dst2; - for (x = 0; x < ww; x++) - { - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - } - src_8 = (uae_u8*)src_32; - dst_8 = (uae_u8*)dst_32; - for (x = 0; x < xxd; x++) - { - BLT_FUNC (src_8, dst_8); - src_8++; - dst_8++; - } - dst2 += dstpitch; - src2 += srcpitch; - } -} -#else -static void NOINLINE BLT_NAME (unsigned int w, unsigned int h, uae_u8 *src, uae_u8 *dst, int srcpitch, int dstpitch) -{ - uae_u8 *src2 = src; - uae_u8 *dst2 = dst; - uae_u32 *src2_32 = (uae_u32*)src; - uae_u32 *dst2_32 = (uae_u32*)dst; - unsigned int y, x, ww, xxd; -#ifdef BLT_TEMP -#if BLT_SIZE == 4 - uae_u32 tmp; -#elif BLT_SIZE == 2 - uae_u16 tmp; -#else - uae_u8 tmp; -#endif -#endif - - if (w < 8 * BLT_MULT) - { - ww = w / BLT_MULT; - for(y = 0; y < h; y++) - { - uae_u32 *src_32 = (uae_u32*)src2; - uae_u32 *dst_32 = (uae_u32*)dst2; - for (x = 0; x < ww; x++) - { - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - } -#if BLT_SIZE == 2 - if (w & 1) - { - uae_u16 *src_16 = (uae_u16*)src_32; - uae_u16 *dst_16 = (uae_u16*)dst_32; - BLT_FUNC (src_16, dst_16); - } -#elif BLT_SIZE == 1 - { - int wb = w & 3; - uae_u8 *src_8 = (uae_u8*)src_32; - uae_u8 *dst_8 = (uae_u8*)dst_32; - while (wb--) - { - BLT_FUNC (src_8, dst_8); - src_8++; - dst_8++; - } - } -#endif - dst2 += dstpitch; - src2 += srcpitch; - } - return; - } - - ww = w / (8 * BLT_MULT); - xxd = (w - ww * (8 * BLT_MULT)) / BLT_MULT; - for(y = 0; y < h; y++) - { - uae_u32 *src_32 = (uae_u32*)src2; - uae_u32 *dst_32 = (uae_u32*)dst2; - for (x = 0; x < ww; x++) - { - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - } - for (x = 0; x < xxd; x++) - { - BLT_FUNC (src_32, dst_32); - src_32++; - dst_32++; - } -#if BLT_SIZE == 2 - if (w & 1) - { - uae_u16 *src_16 = (uae_u16*)src_32; - uae_u16 *dst_16 = (uae_u16*)dst_32; - BLT_FUNC (src_16, dst_16); - } -#elif BLT_SIZE == 1 - { - int wb = w & 3; - uae_u8 *src_8 = (uae_u8*)src_32; - uae_u8 *dst_8 = (uae_u8*)dst_32; - while (wb--) - { - BLT_FUNC (src_8, dst_8); - src_8++; - dst_8++; - } - } -#endif - dst2 += dstpitch; - src2 += srcpitch; - } -} -#endif -#undef BLT_NAME -#undef BLT_FUNC -#ifdef BLT_TEMP -#undef BLT_TEMP -#endif + +#if BLT_SIZE == 3 +static void NOINLINE BLT_NAME (unsigned int w, unsigned int h, uae_u8 *src, uae_u8 *dst, int srcpitch, int dstpitch) +{ + uae_u8 *src2 = src; + uae_u8 *dst2 = dst; + uae_u32 *src2_32 = (uae_u32*)src; + uae_u32 *dst2_32 = (uae_u32*)dst; + unsigned int y, x, ww, xxd; +#ifdef BLT_TEMP + uae_u32 tmp; +#endif + w *= BLT_SIZE; + ww = w / 4; + xxd = w - (ww * 4); + for(y = 0; y < h; y++) + { + uae_u8 *src_8; + uae_u8 *dst_8; + uae_u32 *src_32 = (uae_u32*)src2; + uae_u32 *dst_32 = (uae_u32*)dst2; + for (x = 0; x < ww; x++) + { + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + } + src_8 = (uae_u8*)src_32; + dst_8 = (uae_u8*)dst_32; + for (x = 0; x < xxd; x++) + { + BLT_FUNC (src_8, dst_8); + src_8++; + dst_8++; + } + dst2 += dstpitch; + src2 += srcpitch; + } +} +#else +static void NOINLINE BLT_NAME (unsigned int w, unsigned int h, uae_u8 *src, uae_u8 *dst, int srcpitch, int dstpitch) +{ + uae_u8 *src2 = src; + uae_u8 *dst2 = dst; + uae_u32 *src2_32 = (uae_u32*)src; + uae_u32 *dst2_32 = (uae_u32*)dst; + unsigned int y, x, ww, xxd; +#ifdef BLT_TEMP +#if BLT_SIZE == 4 + uae_u32 tmp; +#elif BLT_SIZE == 2 + uae_u16 tmp; +#else + uae_u8 tmp; +#endif +#endif + + if (w < 8 * BLT_MULT) + { + ww = w / BLT_MULT; + for(y = 0; y < h; y++) + { + uae_u32 *src_32 = (uae_u32*)src2; + uae_u32 *dst_32 = (uae_u32*)dst2; + for (x = 0; x < ww; x++) + { + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + } +#if BLT_SIZE == 2 + if (w & 1) + { + uae_u16 *src_16 = (uae_u16*)src_32; + uae_u16 *dst_16 = (uae_u16*)dst_32; + BLT_FUNC (src_16, dst_16); + } +#elif BLT_SIZE == 1 + { + int wb = w & 3; + uae_u8 *src_8 = (uae_u8*)src_32; + uae_u8 *dst_8 = (uae_u8*)dst_32; + while (wb--) + { + BLT_FUNC (src_8, dst_8); + src_8++; + dst_8++; + } + } +#endif + dst2 += dstpitch; + src2 += srcpitch; + } + return; + } + + ww = w / (8 * BLT_MULT); + xxd = (w - ww * (8 * BLT_MULT)) / BLT_MULT; + for(y = 0; y < h; y++) + { + uae_u32 *src_32 = (uae_u32*)src2; + uae_u32 *dst_32 = (uae_u32*)dst2; + for (x = 0; x < ww; x++) + { + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + } + for (x = 0; x < xxd; x++) + { + BLT_FUNC (src_32, dst_32); + src_32++; + dst_32++; + } +#if BLT_SIZE == 2 + if (w & 1) + { + uae_u16 *src_16 = (uae_u16*)src_32; + uae_u16 *dst_16 = (uae_u16*)dst_32; + BLT_FUNC (src_16, dst_16); + } +#elif BLT_SIZE == 1 + { + int wb = w & 3; + uae_u8 *src_8 = (uae_u8*)src_32; + uae_u8 *dst_8 = (uae_u8*)dst_32; + while (wb--) + { + BLT_FUNC (src_8, dst_8); + src_8++; + dst_8++; + } + } +#endif + dst2 += dstpitch; + src2 += srcpitch; + } +} +#endif +#undef BLT_NAME +#undef BLT_FUNC +#ifdef BLT_TEMP +#undef BLT_TEMP +#endif diff --git a/src/sinctable.cpp b/src/sinctable.cpp index 2008d8be..7e7b857c 100644 --- a/src/sinctable.cpp +++ b/src/sinctable.cpp @@ -1,631 +1,631 @@ -/* - * Table generated by contrib/sinc-integral.py. - */ - -/* tables are: a500 off, a500 on, a1200 off, a1200 on, vanilla. */ -const int winsinc_integral[5][SINC_QUEUE_MAX_AGE] = -{ - { - 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, - 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131070, - 131070,131070,131070,131070,131069,131069,131069,131069,131068,131068,131067,131067, - 131066,131066,131065,131065,131064,131063,131062,131062,131061,131060,131058,131057, - 131056,131055,131053,131051,131050,131048,131046,131043,131041,131039,131036,131033, - 131030,131027,131023,131019,131016,131011,131007,131002,130997,130992,130986,130980, - 130973,130967,130959,130952,130944,130935,130926,130917,130907,130896,130885,130873, - 130861,130848,130835,130820,130805,130789,130773,130756,130737,130718,130698,130677, - 130655,130633,130609,130584,130557,130530,130502,130472,130441,130408,130375,130339, - 130303,130265,130225,130184,130141,130096,130050,130002,129952,129900,129846,129790, - 129732,129672,129609,129545,129478,129409,129337,129263,129186,129107,129025,128940, - 128852,128762,128669,128572,128473,128370,128264,128155,128043,127927,127807,127684, - 127558,127428,127293,127156,127014,126868,126718,126564,126406,126243,126076,125905, - 125729,125549,125364,125174,124980,124780,124576,124367,124152,123933,123708,123478, - 123243,123002,122756,122505,122247,121985,121716,121442,121162,120876,120584,120286, - 119982,119672,119356,119033,118705,118370,118029,117682,117328,116967,116601,116228, - 115848,115462,115069,114670,114264,113851,113432,113006,112573,112134,111688,111236, - 110777,110311,109838,109359,108874,108381,107882,107377,106865,106346,105821,105290, - 104752,104208,103657,103100,102537,101968,101392,100811,100224,99630,99031,98426, - 97816,97199,96578,95950,95318,94680,94037,93389,92736,92079,91416,90749,90077,89401, - 88721,88037,87348,86656,85960,85260,84557,83851,83141,82429,81713,80995,80274,79551, - 78826,78098,77369,76638,75905,75171,74435,73699,72961,72223,71484,70745,70006,69266, - 68527,67788,67050,66312,65576,64840,64106,63373,62641,61912,61184,60459,59736,59015, - 58297,57582,56871,56162,55457,54755,54058,53364,52674,51989,51308,50632,49960,49294, - 48632,47976,47325,46680,46041,45407,44780,44158,43543,42934,42332,41737,41148,40566, - 39991,39424,38863,38310,37765,37227,36696,36173,35659,35152,34652,34161,33678,33204, - 32737,32279,31828,31387,30953,30528,30112,29704,29304,28913,28530,28155,27790,27432, - 27083,26743,26411,26087,25772,25465,25166,24875,24593,24318,24052,23794,23543,23300, - 23066,22838,22619,22406,22202,22004,21814,21631,21454,21285,21122,20966,20816,20673, - 20536,20404,20279,20160,20046,19938,19835,19738,19645,19558,19475,19396,19322,19253, - 19187,19126,19068,19014,18963,18915,18871,18830,18791,18755,18721,18690,18661,18633, - 18608,18584,18561,18540,18520,18501,18483,18465,18448,18431,18414,18398,18381,18364, - 18347,18329,18310,18291,18270,18249,18226,18203,18177,18150,18122,18092,18060,18026, - 17990,17951,17911,17868,17823,17775,17725,17672,17617,17559,17498,17434,17368,17298, - 17226,17150,17072,16990,16906,16818,16727,16634,16537,16437,16334,16228,16119,16007, - 15892,15774,15653,15529,15403,15273,15141,15006,14868,14728,14585,14440,14293,14143, - 13990,13836,13680,13521,13361,13198,13035,12869,12702,12533,12363,12192,12019,11846, - 11671,11496,11320,11143,10966,10789,10611,10433,10255,10076,9898,9721,9543,9367,9190, - 9015,8840,8666,8493,8322,8151,7982,7814,7648,7484,7321,7160,7002,6845,6690,6537, - 6387,6239,6094,5951,5811,5673,5538,5406,5277,5151,5027,4907,4790,4676,4565,4458, - 4354,4253,4155,4061,3970,3882,3798,3718,3640,3567,3496,3430,3366,3306,3250,3197, - 3147,3100,3057,3018,2981,2948,2918,2892,2868,2847,2830,2815,2804,2795,2789,2786, - 2785,2787,2792,2799,2809,2820,2834,2851,2869,2889,2911,2935,2961,2988,3017,3048, - 3079,3113,3147,3182,3218,3256,3294,3332,3372,3412,3452,3493,3534,3575,3616,3657, - 3698,3739,3780,3820,3860,3899,3937,3975,4012,4048,4083,4118,4151,4183,4213,4243, - 4271,4297,4323,4346,4368,4389,4407,4424,4440,4453,4465,4474,4482,4488,4492,4494, - 4494,4491,4487,4481,4472,4462,4449,4435,4418,4399,4378,4355,4330,4303,4274,4243, - 4210,4176,4139,4100,4060,4017,3973,3927,3880,3831,3780,3728,3674,3619,3562,3504, - 3445,3384,3323,3260,3196,3132,3066,2999,2932,2864,2796,2727,2657,2587,2516,2446, - 2375,2304,2232,2161,2090,2019,1948,1878,1807,1738,1668,1599,1531,1464,1397,1331, - 1266,1201,1138,1076,1015,954,896,838,782,726,673,620,570,520,473,426,382,339,297, - 258,220,184,149,116,86,56,29,4,-20,-42,-62,-80,-96,-111,-123,-134,-143,-151,-156, - -160,-162,-162,-161,-158,-153,-147,-139,-130,-119,-107,-93,-78,-61,-43,-24,-4,17,40, - 64,89,114,141,168,197,226,256,286,318,349,381,414,447,481,514,548,582,616,651,685, - 719,753,787,821,854,887,920,953,985,1016,1047,1077,1107,1136,1164,1192,1218,1244, - 1269,1293,1316,1338,1359,1379,1398,1416,1433,1449,1463,1477,1489,1500,1509,1518, - 1525,1531,1536,1539,1541,1542,1542,1541,1538,1534,1528,1522,1514,1505,1495,1483, - 1471,1457,1442,1426,1409,1391,1372,1352,1331,1309,1286,1262,1238,1212,1186,1159, - 1131,1102,1073,1044,1013,983,951,919,887,855,822,789,755,722,688,654,620,586,552, - 518,484,451,417,384,351,318,285,253,221,190,159,129,99,69,41,12,-15,-42,-68,-93, - -118,-142,-165,-187,-209,-229,-249,-268,-285,-302,-318,-333,-347,-361,-373,-384, - -394,-403,-412,-419,-425,-430,-435,-438,-440,-442,-442,-442,-440,-438,-435,-431, - -426,-420,-413,-405,-397,-388,-378,-367,-356,-344,-331,-318,-304,-289,-274,-258, - -242,-225,-208,-191,-173,-154,-136,-117,-97,-78,-58,-38,-18,2,22,43,63,83,104,124, - 144,164,184,204,223,243,262,281,299,317,335,352,369,386,402,418,433,448,462,475, - 488,501,513,524,535,545,554,563,571,579,586,592,597,602,606,610,612,615,616,617, - 617,616,615,613,610,607,603,599,593,588,581,574,567,559,550,541,532,521,511,500, - 488,476,464,451,438,424,411,397,382,368,353,338,322,307,291,275,259,243,227,211, - 195,179,163,147,130,115,99,83,67,52,37,21,7,-8,-22,-36,-50,-64,-77,-90,-103,-115, - -127,-138,-149,-160,-170,-180,-189,-198,-207,-215,-222,-229,-236,-242,-248,-253, - -258,-262,-266,-269,-272,-274,-276,-277,-278,-278,-278,-278,-277,-275,-273,-271, - -268,-265,-262,-258,-253,-248,-243,-238,-232,-226,-219,-212,-205,-198,-190,-182, - -174,-166,-157,-148,-139,-130,-121,-112,-102,-92,-83,-73,-63,-53,-43,-33,-23,-13,-3, - 7,17,27,36,46,55,65,74,83,92,101,109,118,126,134,141,149,156,163,170,177,183,189, - 194,200,205,210,214,218,222,226,229,232,234,237,239,240,241,242,243,243,244,243, - 243,242,241,239,237,235,233,230,227,224,221,217,213,209,205,200,196,191,186,180, - 175,169,163,157,151,145,139,132,126,119,113,106,99,92,85,79,72,65,58,51,44,37,31, - 24,17,11,4,-2,-9,-15,-21,-27,-33,-39,-44,-50,-55,-60,-65,-70,-74,-79,-83,-87,-91, - -95,-98,-102,-105,-108,-110,-113,-115,-117,-119,-121,-122,-123,-124,-125,-126,-126, - -126,-126,-126,-126,-125,-124,-123,-122,-121,-119,-118,-116,-114,-112,-110,-107, - -105,-102,-99,-96,-93,-90,-86,-83,-80,-76,-72,-69,-65,-61,-57,-53,-49,-45,-41,-37, - -33,-29,-25,-21,-17,-13,-8,-4,0,3,7,11,15,19,22,26,30,33,36,40,43,46,49,52,55,57, - 60,62,65,67,69,71,73,74,76,78,79,80,81,82,83,84,84,85,85,85,85,85,85,85,85,84,83, - 83,82,81,80,79,77,76,75,73,72,70,68,66,64,62,60,58,56,54,52,49,47,45,42,40,37,35, - 32,30,27,25,22,20,17,15,12,10,8,5,3,0,-2,-4,-6,-9,-11,-13,-15,-17,-19,-21,-22,-24, - -26,-27,-29,-30,-32,-33,-34,-35,-37,-38,-39,-39,-40,-41,-42,-42,-43,-43,-43,-44, - -44,-44,-44,-44,-44,-44,-44,-43,-43,-42,-42,-41,-41,-40,-39,-39,-38,-37,-36,-35, - -34,-33,-32,-31,-29,-28,-27,-26,-24,-23,-22,-20,-19,-18,-16,-15,-14,-12,-11,-9,-8, - -6,-5,-4,-2,-1,0,2,3,4,6,7,8,9,10,12,13,14,15,16,17,18,18,19,20,21,22,22,23,23,24, - 24,25,25,26,26,26,27,27,27,27,27,27,27,27,27,27,27,26,26,26,25,25,25,24,24,23,23, - 22,22,21,21,20,19,19,18,17,16,16,15,14,13,13,12,11,10,9,9,8,7,6,5,5,4,3,2,2,1,0, - -1,-1,-2,-3,-3,-4,-5,-5,-6,-6,-7,-8,-8,-9,-9,-9,-10,-10,-11,-11,-11,-12,-12,-12, - -12,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-12,-12, - -12,-12,-11,-11,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-8,-7,-7,-6,-6,-5,-5,-5,-4,-4, - -3,-3,-3,-2,-2,-1,-1,-1,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,4,4,4,4,4,3,3,3,3,3, - 2,2,2,2,2,1,1,1,1,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-3,-3,-3, - -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3, - -3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0, - 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - }, - { - 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, - 131072,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, - 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, - 131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131070, - 131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131069,131069, - 131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,131069, - 131069,131068,131068,131068,131068,131068,131068,131068,131068,131068,131068,131067, - 131067,131067,131067,131067,131067,131067,131066,131066,131066,131066,131066,131065, - 131065,131065,131065,131064,131064,131064,131064,131063,131063,131062,131062,131062, - 131061,131061,131060,131060,131059,131059,131058,131058,131057,131056,131056,131055, - 131054,131053,131052,131052,131051,131050,131049,131048,131046,131045,131044,131043, - 131041,131040,131038,131037,131035,131034,131032,131030,131028,131026,131024,131022, - 131020,131017,131015,131012,131010,131007,131004,131001,130998,130994,130991,130987, - 130984,130980,130976,130972,130968,130963,130959,130954,130949,130944,130938,130933, - 130927,130921,130915,130909,130902,130895,130888,130881,130873,130865,130857,130849, - 130840,130831,130822,130813,130803,130793,130782,130771,130760,130749,130737,130725, - 130712,130699,130685,130672,130657,130643,130628,130612,130596,130580,130563,130545, - 130528,130509,130490,130471,130451,130430,130409,130388,130365,130343,130319,130295, - 130270,130245,130219,130193,130165,130137,130109,130079,130049,130018,129987,129954, - 129921,129887,129853,129817,129781,129744,129706,129667,129627,129587,129545,129503, - 129459,129415,129370,129324,129276,129228,129179,129129,129078,129026,128972,128918, - 128862,128806,128748,128690,128630,128569,128507,128443,128379,128313,128246,128178, - 128109,128038,127966,127893,127819,127743,127667,127588,127509,127428,127346,127262, - 127177,127091,127004,126915,126824,126732,126639,126545,126449,126351,126252,126152, - 126050,125947,125842,125736,125628,125519,125408,125296,125182,125067,124950,124832, - 124712,124591,124468,124344,124218,124090,123961,123830,123698,123564,123429,123292, - 123154,123014,122872,122729,122585,122438,122291,122141,121990,121838,121684,121528, - 121371,121212,121052,120891,120727,120562,120396,120228,120059,119888,119715,119541, - 119366,119189,119011,118831,118649,118467,118282,118097,117909,117721,117531,117339, - 117146,116952,116757,116560,116361,116161,115960,115758,115554,115349,115143,114935, - 114726,114516,114305,114092,113878,113663,113447,113229,113011,112791,112570,112348, - 112124,111900,111675,111448,111220,110992,110762,110531,110300,110067,109833,109598, - 109363,109126,108889,108650,108411,108171,107930,107688,107445,107201,106957,106712, - 106466,106219,105972,105723,105474,105225,104974,104723,104471,104219,103966,103712, - 103458,103203,102948,102692,102435,102178,101920,101662,101403,101144,100885,100624, - 100364,100103,99841,99579,99317,99054,98791,98527,98264,97999,97735,97470,97204,96939, - 96673,96407,96140,95873,95606,95339,95071,94804,94536,94267,93999,93730,93461,93192, - 92923,92653,92383,92114,91844,91573,91303,91033,90762,90491,90220,89949,89678,89407, - 89136,88865,88593,88321,88050,87778,87506,87234,86962,86690,86418,86146,85874,85602, - 85330,85057,84785,84513,84240,83968,83696,83423,83151,82878,82606,82333,82061,81789, - 81516,81244,80971,80699,80427,80154,79882,79610,79337,79065,78793,78521,78249,77977, - 77705,77433,77161,76889,76617,76345,76074,75802,75531,75259,74988,74717,74446,74175, - 73904,73633,73362,73092,72821,72551,72280,72010,71740,71470,71201,70931,70661,70392, - 70123,69854,69585,69317,69048,68780,68512,68244,67976,67709,67441,67174,66907,66641, - 66374,66108,65842,65576,65311,65046,64781,64516,64252,63988,63724,63460,63197,62934, - 62672,62409,62147,61886,61624,61363,61103,60843,60583,60323,60064,59805,59547,59289, - 59031,58774,58517,58261,58005,57749,57494,57239,56985,56731,56478,56225,55973,55721, - 55470,55219,54968,54718,54469,54220,53971,53724,53476,53229,52983,52737,52492,52247, - 52003,51759,51516,51274,51032,50791,50550,50310,50070,49831,49593,49355,49118,48881, - 48645,48410,48175,47941,47707,47474,47242,47010,46779,46549,46319,46090,45861,45633, - 45406,45179,44953,44728,44503,44279,44056,43833,43611,43389,43168,42948,42728,42510, - 42291,42074,41857,41640,41425,41210,40995,40782,40568,40356,40144,39933,39723,39513, - 39304,39095,38887,38680,38473,38267,38062,37857,37653,37449,37247,37044,36843,36642, - 36442,36242,36043,35845,35647,35450,35253,35057,34862,34667,34473,34280,34087,33894, - 33703,33512,33321,33132,32942,32754,32566,32378,32192,32006,31820,31635,31451,31267, - 31084,30901,30719,30538,30357,30177,29997,29818,29640,29462,29285,29108,28932,28756, - 28581,28407,28233,28060,27888,27716,27545,27374,27204,27034,26865,26697,26529,26362, - 26195,26029,25863,25699,25534,25371,25207,25045,24883,24722,24561,24401,24241,24082, - 23924,23766,23609,23453,23297,23142,22987,22833,22679,22526,22374,22222,22071,21921, - 21771,21622,21473,21325,21177,21031,20884,20739,20594,20449,20306,20162,20020,19878, - 19737,19596,19456,19316,19178,19039,18902,18765,18628,18493,18358,18223,18089,17956, - 17823,17691,17560,17429,17299,17169,17040,16912,16784,16657,16531,16405,16280,16155, - 16031,15908,15785,15663,15541,15420,15300,15180,15061,14942,14824,14707,14590,14474, - 14358,14243,14129,14015,13901,13789,13677,13565,13454,13344,13234,13125,13016,12908, - 12801,12694,12588,12482,12377,12272,12168,12064,11961,11859,11757,11655,11554,11454, - 11354,11255,11156,11058,10960,10863,10766,10670,10575,10480,10385,10291,10197,10104, - 10012,9920,9828,9737,9646,9556,9466,9377,9289,9200,9113,9025,8939,8852,8766,8681, - 8596,8512,8428,8344,8261,8178,8096,8014,7933,7852,7772,7692,7612,7533,7455,7376, - 7299,7221,7144,7068,6992,6916,6841,6766,6692,6618,6544,6471,6398,6326,6254,6182, - 6111,6041,5970,5901,5831,5762,5693,5625,5557,5490,5423,5356,5290,5224,5159,5093, - 5029,4965,4901,4837,4774,4711,4649,4587,4525,4464,4404,4343,4283,4224,4164,4105, - 4047,3989,3931,3874,3817,3760,3704,3648,3593,3538,3483,3429,3375,3321,3268,3215, - 3163,3111,3059,3008,2957,2906,2856,2806,2756,2707,2658,2610,2562,2514,2466,2419, - 2373,2326,2280,2235,2189,2144,2100,2056,2012,1968,1925,1882,1839,1797,1755,1714, - 1672,1631,1591,1551,1511,1471,1432,1393,1354,1316,1278,1240,1203,1165,1129,1092, - 1056,1020,984,949,914,879,845,811,777,743,710,677,644,612,580,548,516,485,454,423, - 393,362,332,303,273,244,215,186,158,129,101,74,46,19,-8,-35,-61,-88,-114,-140,-165, - -191,-216,-241,-265,-290,-314,-338,-362,-386,-409,-432,-455,-478,-501,-523,-545, - -567,-589,-610,-632,-653,-674,-694,-715,-735,-756,-775,-795,-815,-834,-853,-872, - -891,-910,-928,-947,-965,-983,-1000,-1018,-1035,-1052,-1069,-1086,-1103,-1119,-1136, - -1152,-1168,-1184,-1199,-1215,-1230,-1245,-1260,-1275,-1289,-1304,-1318,-1332,-1346, - -1360,-1373,-1387,-1400,-1413,-1426,-1439,-1452,-1464,-1477,-1489,-1501,-1513,-1524, - -1536,-1547,-1558,-1570,-1581,-1591,-1602,-1612,-1623,-1633,-1643,-1653,-1663,-1672, - -1682,-1691,-1700,-1709,-1718,-1727,-1735,-1744,-1752,-1760,-1768,-1776,-1784,-1792, - -1799,-1807,-1814,-1821,-1828,-1835,-1842,-1848,-1855,-1861,-1867,-1873,-1879,-1885, - -1891,-1896,-1902,-1907,-1913,-1918,-1923,-1928,-1932,-1937,-1942,-1946,-1950,-1955, - -1959,-1963,-1967,-1971,-1974,-1978,-1981,-1985,-1988,-1991,-1994,-1997,-2000,-2003, - -2006,-2009,-2011,-2013,-2016,-2018,-2020,-2022,-2024,-2026,-2028,-2030,-2032,-2033, - -2035,-2036,-2037,-2039,-2040,-2041,-2042,-2043,-2044,-2045,-2045,-2046,-2047,-2047, - -2048,-2048,-2048,-2049,-2049,-2049,-2049,-2049,-2049,-2049,-2049,-2048,-2048,-2048, - -2047,-2047,-2046,-2046,-2045,-2044,-2043,-2043,-2042,-2041,-2040,-2039,-2038,-2036, - -2035,-2034,-2033,-2031,-2030,-2028,-2027,-2025,-2024,-2022,-2020,-2019,-2017,-2015, - -2013,-2011,-2009,-2007,-2005,-2003,-2001,-1998,-1996,-1994,-1992,-1989,-1987,-1984, - -1982,-1979,-1977,-1974,-1971,-1969,-1966,-1963,-1960,-1957,-1954,-1952,-1949,-1946, - -1942,-1939,-1936,-1933,-1930,-1927,-1923,-1920,-1917,-1913,-1910,-1906,-1903,-1899, - -1896,-1892,-1889,-1885,-1881,-1878,-1874,-1870,-1866,-1863,-1859,-1855,-1851,-1847, - -1843,-1839,-1835,-1831,-1827,-1823,-1819,-1814,-1810,-1806,-1802,-1798,-1793,-1789, - -1785,-1780,-1776,-1771,-1767,-1763,-1758,-1754,-1749,-1745,-1740,-1736,-1731,-1726, - -1722,-1717,-1713,-1708,-1703,-1698,-1694,-1689,-1684,-1680,-1675,-1670,-1665,-1660, - -1656,-1651,-1646,-1641,-1636,-1631,-1626,-1622,-1617,-1612,-1607,-1602,-1597,-1592, - -1587,-1582,-1577,-1572,-1567,-1562,-1557,-1552,-1547,-1542,-1537,-1532,-1527,-1522, - -1517,-1512,-1507,-1502,-1497,-1492,-1487,-1482,-1477,-1471,-1466,-1461,-1456,-1451, - -1446,-1441,-1436,-1431,-1426,-1421,-1416,-1411,-1406,-1401,-1395,-1390,-1385,-1380, - -1375,-1370,-1365,-1360,-1355,-1350,-1345,-1340,-1335,-1330,-1325,-1320,-1315,-1310, - -1305,-1300,-1295,-1290,-1285,-1280,-1275,-1270,-1265,-1260,-1255,-1250,-1245,-1240, - -1235,-1230,-1225,-1220,-1215,-1210,-1205,-1200,-1195,-1190,-1185,-1180,-1175,-1171, - -1166,-1161,-1156,-1151,-1146,-1141,-1136,-1131,-1127,-1122,-1117,-1112,-1107,-1102, - -1098,-1093,-1088,-1083,-1078,-1074,-1069,-1064,-1059,-1055,-1050,-1045,-1040,-1036, - -1031,-1026,-1022,-1017,-1012,-1007,-1003,-998,-994,-989,-984,-980,-975,-970,-966, - -961,-957,-952,-948,-943,-938,-934,-929,-925,-920,-916,-911,-907,-902,-898,-894, - -889,-885,-880,-876,-872,-867,-863,-858,-854,-850,-845,-841,-837,-833,-828,-824, - -820,-816,-811,-807,-803,-799,-795,-790,-786,-782,-778,-774,-770,-766,-762,-757, - -753,-749,-745,-741,-737,-733,-729,-725,-721,-717,-714,-710,-706,-702,-698,-694, - -690,-686,-683,-679,-675,-671,-667,-664,-660,-656,-652,-649,-645,-641,-638,-634, - -630,-627,-623,-620,-616,-612,-609,-605,-602,-598,-595,-591,-588,-584,-581,-577, - -574,-571,-567,-564,-560,-557,-554,-550,-547,-544,-540,-537,-534,-530,-527,-524, - -521,-518,-514,-511,-508,-505,-502,-499,-495,-492,-489,-486,-483,-480,-477,-474, - -471,-468,-465,-462,-459,-456,-453,-450,-447,-444,-441,-438,-435,-433,-430,-427, - -424,-421,-418,-416,-413,-410,-407,-405,-402,-399,-396,-394,-391,-388,-386,-383, - -380,-378,-375,-373,-370,-367,-365,-362,-360,-357,-355,-352,-350,-347,-345,-342, - -340,-337,-335,-333,-330,-328,-325,-323,-321,-318,-316,-314,-311,-309,-307,-305, - -302,-300,-298,-296,-293,-291,-289,-287,-285,-282,-280,-278,-276,-274,-272,-270, - -268,-266,-264,-261,-259,-257,-255,-253,-251,-249,-247,-246,-244,-242,-240,-238, - -236,-234,-232,-230,-228,-227,-225,-223,-221,-219,-217,-216,-214,-212,-210,-209, - -207,-205,-203,-202,-200,-198,-197,-195,-193,-192,-190,-188,-187,-185,-184,-182, - -180,-179,-177,-176,-174,-173,-171,-170,-168,-167,-165,-164,-162,-161,-159,-158, - -156,-155,-154,-152,-151,-149,-148,-147,-145,-144,-143,-141,-140,-139,-137,-136, - -135,-133,-132,-131,-130,-128,-127,-126,-125,-123,-122,-121,-120,-119,-117,-116, - -115,-114,-113,-112,-111,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98, - -97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78, - -78,-77,-76,-75,-74,-73,-72,-71,-71,-70,-69,-68,-67,-67,-66,-65,-64,-63,-63,-62, - -61,-60,-60,-59,-58,-58,-57,-56,-55,-55,-54,-53,-53,-52,-51,-51,-50,-49,-49,-48, - -47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36, - -36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-28,-27,-27, - -26,-26,-25,-25,-25,-24,-24,-23,-23,-23,-22,-22,-21,-21,-21,-20,-20,-20,-19,-19, - -19,-18,-18,-17,-17,-17,-17,-16,-16,-16,-15,-15,-15,-14,-14,-14,-13,-13,-13,-13, - -12,-12,-12,-12,-11,-11,-11,-11,-10,-10,-10,-10,-9,-9,-9,-9,-9,-8,-8,-8,-8,-7,-7, - -7,-7,-7,-7,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,-4,-4,-3,-3,-3,-3, - -3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - }, - { - 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, - 131072,131072,131072,131071,131071,131071,131071,131071,131071,131070,131070,131070, - 131070,131069,131069,131069,131068,131068,131067,131066,131066,131065,131064,131063, - 131062,131061,131059,131058,131056,131055,131053,131051,131049,131046,131044,131041, - 131038,131035,131031,131028,131024,131019,131015,131010,131004,130998,130992,130986, - 130979,130971,130963,130955,130945,130936,130925,130914,130903,130890,130877,130863, - 130849,130833,130816,130799,130781,130761,130740,130719,130696,130672,130646,130619, - 130591,130562,130531,130498,130463,130427,130390,130350,130308,130265,130219,130172, - 130122,130069,130015,129958,129898,129836,129772,129704,129633,129560,129483,129404, - 129321,129235,129145,129051,128954,128854,128749,128640,128527,128410,128289,128163, - 128033,127898,127758,127613,127463,127308,127147,126982,126810,126633,126450,126261, - 126066,125864,125657,125443,125222,124994,124759,124518,124269,124013,123749,123478, - 123199,122912,122617,122314,122003,121683,121355,121017,120672,120317,119953,119579, - 119197,118805,118403,117992,117570,117139,116698,116246,115784,115312,114829,114336, - 113831,113316,112790,112253,111705,111145,110575,109992,109399,108794,108177,107549, - 106909,106257,105594,104918,104231,103532,102821,102098,101363,100616,99858,99087, - 98304,97510,96703,95885,95054,94212,93358,92493,91616,90727,89827,88915,87992,87058, - 86113,85157,84190,83212,82224,81225,80216,79196,78167,77128,76079,75021,73953,72877, - 71792,70698,69596,68485,67367,66241,65108,63967,62820,61666,60506,59339,58168,56990, - 55808,54621,53429,52234,51034,49832,48626,47417,46206,44994,43779,42563,41347,40130, - 38913,37696,36480,35265,34052,32841,31632,30426,29223,28023,26828,25637,24451,23270, - 22095,20926,19764,18609,17461,16321,15190,14067,12953,11849,10755,9671,8598,7537, - 6487,5449,4423,3410,2411,1425,453,-504,-1447,-2375,-3287,-4184,-5064,-5928,-6775, - -7605,-8417,-9212,-9989,-10747,-11487,-12208,-12910,-13592,-14255,-14898,-15521, - -16124,-16706,-17268,-17809,-18329,-18829,-19306,-19763,-20198,-20612,-21004,-21374, - -21723,-22050,-22355,-22639,-22900,-23140,-23358,-23555,-23729,-23883,-24014,-24124, - -24213,-24281,-24328,-24353,-24359,-24343,-24307,-24251,-24175,-24079,-23964,-23830, - -23677,-23505,-23314,-23106,-22879,-22636,-22375,-22097,-21804,-21494,-21168,-20827, - -20472,-20102,-19718,-19320,-18909,-18486,-18050,-17603,-17144,-16674,-16194,-15705, - -15205,-14697,-14181,-13657,-13125,-12587,-12042,-11491,-10936,-10375,-9810,-9242, - -8670,-8096,-7520,-6942,-6363,-5783,-5204,-4625,-4047,-3471,-2897,-2325,-1756,-1191, - -630,-74,477,1023,1563,2096,2623,3142,3654,4157,4652,5138,5614,6081,6537,6983,7418, - 7842,8255,8655,9044,9420,9783,10134,10471,10795,11105,11401,11684,11952,12205,12444, - 12669,12878,13073,13252,13417,13567,13701,13820,13924,14012,14086,14144,14187,14215, - 14228,14226,14209,14178,14132,14071,13996,13907,13805,13688,13558,13415,13259,13089, - 12908,12714,12508,12290,12061,11821,11570,11309,11038,10756,10466,10166,9858,9542, - 9218,8886,8547,8201,7850,7492,7129,6761,6388,6011,5631,5247,4860,4471,4080,3687, - 3294,2899,2504,2110,1716,1323,931,541,154,-231,-613,-991,-1365,-1736,-2101,-2462, - -2817,-3166,-3510,-3847,-4177,-4500,-4816,-5124,-5424,-5716,-5999,-6273,-6539,-6795, - -7042,-7279,-7506,-7722,-7929,-8125,-8310,-8485,-8649,-8802,-8943,-9074,-9193,-9300, - -9397,-9481,-9555,-9617,-9667,-9706,-9733,-9749,-9754,-9748,-9730,-9701,-9661,-9610, - -9548,-9476,-9393,-9300,-9196,-9083,-8960,-8827,-8685,-8534,-8373,-8204,-8027,-7842, - -7648,-7447,-7238,-7023,-6801,-6572,-6337,-6096,-5849,-5598,-5341,-5080,-4815,-4545, - -4273,-3997,-3718,-3436,-3153,-2867,-2581,-2293,-2004,-1715,-1425,-1136,-848,-560, - -274,11,293,574,852,1127,1399,1667,1932,2192,2448,2699,2946,3187,3423,3653,3877, - 4095,4306,4511,4709,4900,5084,5261,5430,5591,5744,5889,6026,6155,6276,6388,6492, - 6587,6673,6750,6819,6879,6931,6973,7007,7031,7047,7055,7053,7043,7024,6997,6962, - 6918,6866,6805,6737,6661,6577,6486,6387,6281,6168,6048,5922,5789,5650,5504,5353, - 5196,5034,4866,4694,4517,4336,4150,3960,3767,3571,3371,3168,2963,2755,2546,2334, - 2122,1907,1692,1477,1261,1044,828,612,397,183,-30,-241,-451,-659,-864,-1067,-1268, - -1465,-1659,-1850,-2037,-2221,-2400,-2575,-2746,-2912,-3073,-3230,-3381,-3527,-3667, - -3802,-3931,-4054,-4172,-4283,-4388,-4487,-4579,-4665,-4745,-4818,-4884,-4944,-4997, - -5043,-5082,-5115,-5141,-5160,-5173,-5179,-5178,-5171,-5157,-5136,-5110,-5076,-5037, - -4991,-4940,-4882,-4819,-4749,-4675,-4594,-4509,-4418,-4322,-4221,-4116,-4006,-3891, - -3772,-3650,-3523,-3393,-3259,-3123,-2983,-2840,-2694,-2546,-2396,-2244,-2090,-1934, - -1777,-1619,-1459,-1299,-1139,-978,-817,-655,-495,-334,-175,-16,141,298,452,605,757, - 906,1053,1197,1339,1478,1615,1748,1878,2004,2127,2247,2362,2474,2582,2685,2785, - 2880,2970,3056,3137,3214,3286,3353,3415,3473,3525,3572,3615,3652,3684,3711,3733, - 3750,3762,3769,3771,3768,3760,3747,3729,3707,3680,3648,3611,3570,3525,3476,3422, - 3364,3302,3236,3166,3093,3016,2936,2852,2766,2676,2583,2488,2390,2290,2187,2082, - 1976,1867,1757,1645,1532,1418,1303,1187,1070,952,835,717,599,481,363,246,129,13, - -102,-216,-329,-440,-550,-659,-766,-871,-974,-1075,-1174,-1270,-1364,-1456,-1544, - -1630,-1714,-1794,-1871,-1945,-2016,-2084,-2148,-2209,-2267,-2321,-2372,-2418,-2462, - -2502,-2538,-2570,-2599,-2624,-2645,-2662,-2676,-2686,-2693,-2695,-2694,-2690,-2682, - -2670,-2655,-2636,-2614,-2589,-2560,-2528,-2493,-2455,-2414,-2370,-2323,-2274,-2221, - -2167,-2109,-2050,-1988,-1923,-1857,-1789,-1719,-1647,-1574,-1499,-1422,-1345,-1266, - -1186,-1105,-1023,-941,-858,-774,-690,-606,-522,-438,-354,-270,-187,-104,-21,61,142, - 222,301,379,456,532,606,679,750,820,888,954,1018,1081,1141,1199,1255,1309,1361, - 1410,1457,1502,1544,1584,1621,1655,1687,1717,1743,1768,1789,1808,1824,1838,1849, - 1857,1863,1866,1867,1864,1860,1853,1843,1831,1816,1800,1780,1759,1735,1709,1681, - 1651,1619,1585,1549,1511,1472,1431,1388,1344,1298,1251,1202,1153,1102,1050,997,943, - 889,833,778,721,664,607,549,491,433,375,317,259,201,143,86,29,-27,-83,-138,-193, - -246,-299,-351,-402,-452,-501,-548,-595,-640,-684,-726,-767,-807,-845,-882,-917, - -950,-982,-1012,-1040,-1067,-1091,-1115,-1136,-1155,-1173,-1189,-1203,-1215,-1226, - -1235,-1241,-1246,-1250,-1251,-1251,-1249,-1245,-1239,-1232,-1223,-1213,-1201,-1187, - -1172,-1155,-1137,-1117,-1096,-1074,-1051,-1026,-1000,-973,-944,-915,-885,-854,-822, - -789,-755,-720,-685,-650,-613,-577,-539,-502,-464,-426,-387,-349,-310,-272,-233, - -194,-156,-118,-80,-42,-4,33,69,105,141,176,210,244,277,309,341,372,401,430,458,485, - 512,537,561,584,606,626,646,665,682,698,713,727,740,751,762,771,778,785,791,795, - 798,800,801,800,799,796,792,787,781,774,766,757,747,736,724,711,697,682,667,650, - 633,616,597,578,558,538,517,496,474,452,429,406,382,359,335,311,286,262,237,213, - 188,163,139,114,90,65,41,17,-6,-30,-53,-75,-98,-120,-141,-162,-183,-203,-222,-241, - -260,-277,-295,-311,-327,-342,-357,-371,-384,-396,-408,-419,-429,-439,-448,-456, - -463,-469,-475,-480,-484,-488,-490,-492,-493,-494,-493,-492,-491,-488,-485,-481, - -477,-472,-466,-460,-453,-445,-437,-428,-419,-410,-399,-389,-378,-366,-354,-342, - -329,-316,-303,-290,-276,-262,-248,-233,-218,-204,-189,-174,-159,-144,-129,-114,-99, - -84,-69,-54,-39,-24,-10,4,18,32,46,59,73,85,98,110,122,134,145,156,167,177,186,196, - 205,213,221,229,236,243,249,255,260,265,269,273,277,280,282,284,286,287,288,288, - 288,287,286,285,283,281,278,275,272,268,264,259,254,249,244,238,232,225,219,212, - 205,198,190,182,175,167,158,150,142,133,125,116,107,98,90,81,72,63,54,46,37,28,20, - 11,3,-5,-13,-21,-29,-37,-45,-52,-59,-66,-73,-79,-86,-92,-98,-104,-109,-114,-119, - -124,-128,-132,-136,-140,-143,-146,-149,-152,-154,-156,-158,-159,-160,-161,-162, - -162,-163,-162,-162,-161,-161,-159,-158,-157,-155,-153,-151,-148,-146,-143,-140, - -137,-133,-130,-126,-122,-118,-114,-110,-106,-101,-97,-92,-88,-83,-78,-73,-68,-64, - -59,-54,-49,-44,-39,-34,-29,-24,-19,-14,-9,-5,0,5,9,14,18,22,26,30,34,38,42,45,49, - 52,55,58,61,64,67,69,72,74,76,78,79,81,82,84,85,86,86,87,88,88,88,88,88,88,88,87, - 87,86,85,84,83,82,80,79,77,75,74,72,70,68,66,64,61,59,57,54,52,49,47,44,42,39,36, - 34,31,28,25,23,20,17,15,12,9,7,4,2,-1,-3,-6,-8,-10,-12,-15,-17,-19,-21,-23,-25, - -26,-28,-30,-31,-33,-34,-36,-37,-38,-39,-40,-41,-42,-43,-43,-44,-45,-45,-45,-46, - -46,-46,-46,-46,-46,-46,-45,-45,-45,-44,-44,-43,-42,-42,-41,-40,-39,-38,-37,-36, - -35,-34,-33,-32,-30,-29,-28,-27,-25,-24,-23,-21,-20,-18,-17,-16,-14,-13,-11,-10,-9, - -7,-6,-5,-3,-2,-1,1,2,3,4,5,7,8,9,10,11,12,13,14,14,15,16,17,17,18,19,19,20,20,21, - 21,21,22,22,22,22,22,23,23,23,23,23,22,22,22,22,22,21,21,21,20,20,20,19,19,18,18, - 17,16,16,15,15,14,13,13,12,11,11,10,9,9,8,7,7,6,5,5,4,3,3,2,1,1,0,-1,-1,-2,-2,-3, - -3,-4,-4,-5,-5,-6,-6,-7,-7,-7,-8,-8,-8,-9,-9,-9,-9,-10,-10,-10,-10,-10,-10,-10, - -10,-11,-11,-11,-11,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-9,-9,-9,-8,-8,-8,-8,-7, - -7,-7,-7,-6,-6,-6,-5,-5,-5,-4,-4,-4,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,0,0,0,0,1,1,1,2, - 2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4, - 4,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2, - -2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - }, - { - 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, - 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, - 131072,131072,131072,131072,131072,131072,131072,131071,131071,131071,131071,131071, - 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, - 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, - 131071,131071,131071,131071,131071,131070,131070,131070,131070,131070,131070,131070, - 131070,131070,131070,131070,131069,131069,131069,131069,131069,131069,131068,131068, - 131068,131068,131068,131067,131067,131067,131066,131066,131066,131065,131065,131064, - 131064,131064,131063,131062,131062,131061,131061,131060,131059,131058,131058,131057, - 131056,131055,131054,131053,131052,131051,131049,131048,131047,131045,131044,131042, - 131040,131039,131037,131035,131033,131031,131028,131026,131024,131021,131018,131015, - 131012,131009,131006,131003,130999,130995,130991,130987,130983,130978,130974,130969, - 130964,130959,130953,130947,130941,130935,130929,130922,130915,130908,130900,130892, - 130884,130876,130867,130858,130848,130838,130828,130817,130806,130795,130783,130771, - 130758,130745,130731,130717,130702,130687,130671,130655,130638,130621,130603,130585, - 130566,130546,130526,130505,130483,130461,130437,130414,130389,130364,130338,130311, - 130283,130255,130225,130195,130164,130132,130099,130065,130031,129995,129958,129920, - 129881,129841,129800,129758,129715,129671,129625,129578,129531,129481,129431,129379, - 129326,129272,129216,129159,129101,129041,128980,128918,128853,128788,128721,128652, - 128582,128510,128437,128362,128285,128206,128126,128045,127961,127876,127789,127700, - 127609,127517,127422,127326,127228,127128,127026,126922,126816,126708,126598,126486, - 126371,126255,126137,126016,125894,125769,125642,125513,125382,125248,125112,124974, - 124834,124691,124546,124399,124250,124098,123944,123787,123628,123467,123303,123137, - 122969,122798,122625,122449,122271,122090,121907,121722,121534,121343,121150,120955, - 120757,120557,120354,120149,119941,119731,119519,119304,119086,118866,118644,118419, - 118192,117962,117730,117495,117258,117019,116777,116533,116287,116038,115787,115533, - 115277,115019,114759,114496,114232,113965,113695,113424,113150,112874,112597,112317, - 112035,111750,111464,111176,110886,110594,110300,110004,109706,109406,109105,108801, - 108496,108189,107881,107571,107259,106945,106630,106313,105995,105675,105354,105032, - 104708,104382,104056,103728,103398,103068,102736,102403,102070,101735,101398,101061, - 100723,100384,100044,99704,99362,99020,98676,98333,97988,97643,97297,96950,96603, - 96256,95908,95559,95211,94861,94512,94162,93812,93461,93111,92760,92409,92058,91707, - 91356,91005,90654,90303,89952,89601,89250,88899,88549,88199,87849,87499,87150,86801, - 86452,86104,85756,85408,85061,84715,84369,84023,83678,83334,82990,82646,82304,81962, - 81620,81279,80939,80600,80261,79923,79586,79249,78914,78579,78244,77911,77578,77247, - 76916,76585,76256,75927,75600,75273,74947,74622,74297,73974,73651,73329,73008,72688, - 72369,72051,71733,71417,71101,70786,70472,70159,69847,69535,69225,68915,68606,68298, - 67990,67684,67378,67073,66769,66466,66163,65861,65560,65260,64960,64661,64363,64066, - 63769,63473,63178,62884,62590,62296,62004,61712,61421,61130,60840,60550,60262,59973, - 59686,59399,59112,58826,58541,58256,57972,57688,57405,57122,56840,56558,56277,55996, - 55715,55436,55156,54877,54599,54321,54043,53766,53490,53213,52938,52662,52387,52113, - 51839,51565,51292,51019,50747,50475,50203,49932,49661,49391,49121,48852,48583,48314, - 48046,47778,47511,47244,46978,46712,46446,46181,45917,45653,45389,45126,44864,44601, - 44340,44079,43818,43558,43299,43040,42782,42524,42267,42010,41754,41499,41244,40990, - 40737,40484,40232,39980,39729,39479,39230,38981,38733,38486,38239,37994,37749,37504, - 37261,37018,36777,36536,36296,36056,35818,35580,35343,35108,34873,34639,34405,34173, - 33942,33712,33482,33254,33026,32800,32574,32349,32126,31903,31682,31461,31242,31023, - 30806,30589,30374,30160,29946,29734,29523,29313,29104,28896,28689,28483,28278,28074, - 27872,27670,27470,27270,27072,26875,26678,26483,26289,26096,25904,25713,25524,25335, - 25147,24961,24775,24591,24407,24225,24043,23863,23684,23505,23328,23152,22976,22802, - 22628,22456,22285,22114,21945,21776,21608,21442,21276,21111,20947,20784,20622,20460, - 20300,20140,19981,19823,19666,19510,19355,19200,19046,18893,18741,18589,18438,18288, - 18139,17990,17843,17696,17549,17403,17258,17114,16970,16827,16685,16543,16402,16262, - 16122,15983,15845,15707,15569,15433,15296,15161,15026,14891,14758,14624,14492,14359, - 14228,14097,13966,13836,13707,13578,13449,13321,13194,13067,12941,12815,12689,12565, - 12440,12317,12193,12071,11948,11826,11705,11584,11464,11344,11225,11107,10988,10871, - 10753,10637,10521,10405,10290,10175,10061,9948,9835,9722,9610,9499,9388,9278,9168, - 9059,8950,8842,8735,8628,8522,8416,8311,8206,8102,7998,7896,7793,7692,7591,7490, - 7390,7291,7192,7094,6997,6900,6804,6709,6614,6520,6426,6333,6241,6149,6058,5968, - 5878,5789,5700,5613,5526,5439,5353,5268,5184,5100,5017,4935,4853,4772,4691,4611, - 4532,4454,4376,4299,4222,4146,4071,3997,3923,3849,3777,3705,3634,3563,3493,3423, - 3354,3286,3219,3152,3085,3020,2954,2890,2826,2762,2700,2637,2576,2515,2454,2394, - 2335,2276,2218,2160,2102,2046,1989,1934,1878,1824,1769,1716,1662,1610,1557,1505, - 1454,1403,1352,1302,1253,1203,1155,1106,1058,1011,963,917,870,824,778,733,688,643, - 599,555,512,468,425,383,341,299,257,216,175,134,93,53,13,-26,-65,-105,-143,-182, - -220,-258,-296,-333,-370,-407,-444,-480,-516,-552,-588,-623,-659,-694,-728,-763, - -797,-831,-865,-898,-932,-965,-997,-1030,-1062,-1094,-1126,-1158,-1189,-1220,-1251, - -1282,-1312,-1343,-1373,-1402,-1432,-1461,-1490,-1519,-1547,-1575,-1603,-1631,-1659, - -1686,-1713,-1739,-1766,-1792,-1818,-1844,-1869,-1894,-1919,-1944,-1968,-1992,-2016, - -2039,-2063,-2086,-2108,-2131,-2153,-2175,-2196,-2218,-2239,-2259,-2280,-2300,-2320, - -2339,-2359,-2378,-2396,-2415,-2433,-2451,-2469,-2486,-2503,-2520,-2536,-2552,-2568, - -2584,-2599,-2614,-2629,-2644,-2658,-2672,-2686,-2699,-2712,-2725,-2738,-2750,-2762, - -2774,-2786,-2797,-2808,-2819,-2829,-2840,-2850,-2860,-2869,-2878,-2888,-2896,-2905, - -2914,-2922,-2930,-2938,-2945,-2953,-2960,-2967,-2973,-2980,-2986,-2992,-2998,-3004, - -3010,-3015,-3020,-3026,-3030,-3035,-3040,-3044,-3048,-3053,-3057,-3060,-3064,-3068, - -3071,-3074,-3077,-3080,-3083,-3086,-3089,-3091,-3094,-3096,-3098,-3100,-3102,-3104, - -3106,-3108,-3109,-3111,-3112,-3113,-3115,-3116,-3117,-3118,-3119,-3120,-3120,-3121, - -3122,-3122,-3123,-3123,-3123,-3124,-3124,-3124,-3124,-3124,-3124,-3124,-3124,-3123, - -3123,-3123,-3122,-3122,-3121,-3121,-3120,-3120,-3119,-3118,-3117,-3116,-3115,-3114, - -3113,-3112,-3111,-3110,-3108,-3107,-3105,-3104,-3102,-3101,-3099,-3097,-3096,-3094, - -3092,-3090,-3088,-3086,-3083,-3081,-3079,-3076,-3074,-3071,-3069,-3066,-3063,-3061, - -3058,-3055,-3052,-3049,-3045,-3042,-3039,-3035,-3032,-3028,-3025,-3021,-3017,-3013, - -3010,-3005,-3001,-2997,-2993,-2989,-2984,-2980,-2975,-2971,-2966,-2961,-2956,-2951, - -2946,-2941,-2936,-2931,-2925,-2920,-2915,-2909,-2903,-2898,-2892,-2886,-2880,-2874, - -2868,-2862,-2856,-2850,-2843,-2837,-2830,-2824,-2817,-2811,-2804,-2797,-2791,-2784, - -2777,-2770,-2763,-2756,-2749,-2742,-2734,-2727,-2720,-2713,-2705,-2698,-2690,-2683, - -2675,-2668,-2660,-2653,-2645,-2637,-2630,-2622,-2614,-2606,-2599,-2591,-2583,-2575, - -2567,-2559,-2551,-2544,-2536,-2528,-2520,-2512,-2504,-2496,-2488,-2480,-2472,-2464, - -2456,-2448,-2440,-2432,-2424,-2416,-2408,-2400,-2392,-2384,-2376,-2368,-2360,-2352, - -2344,-2336,-2328,-2321,-2313,-2305,-2297,-2289,-2281,-2273,-2266,-2258,-2250,-2242, - -2234,-2227,-2219,-2211,-2203,-2196,-2188,-2180,-2172,-2165,-2157,-2149,-2142,-2134, - -2127,-2119,-2111,-2104,-2096,-2089,-2081,-2074,-2066,-2059,-2051,-2044,-2036,-2029, - -2021,-2014,-2006,-1999,-1991,-1984,-1976,-1969,-1962,-1954,-1947,-1939,-1932,-1925, - -1917,-1910,-1902,-1895,-1888,-1880,-1873,-1865,-1858,-1851,-1843,-1836,-1829,-1821, - -1814,-1806,-1799,-1792,-1784,-1777,-1770,-1762,-1755,-1747,-1740,-1733,-1725,-1718, - -1711,-1703,-1696,-1689,-1681,-1674,-1667,-1659,-1652,-1644,-1637,-1630,-1622,-1615, - -1608,-1600,-1593,-1586,-1578,-1571,-1564,-1556,-1549,-1542,-1535,-1527,-1520,-1513, - -1506,-1498,-1491,-1484,-1477,-1469,-1462,-1455,-1448,-1441,-1433,-1426,-1419,-1412, - -1405,-1398,-1391,-1384,-1377,-1370,-1363,-1356,-1349,-1342,-1335,-1328,-1321,-1314, - -1307,-1300,-1293,-1287,-1280,-1273,-1266,-1260,-1253,-1246,-1240,-1233,-1226,-1220, - -1213,-1207,-1200,-1193,-1187,-1181,-1174,-1168,-1161,-1155,-1149,-1142,-1136,-1130, - -1123,-1117,-1111,-1105,-1099,-1093,-1087,-1081,-1074,-1068,-1062,-1057,-1051,-1045, - -1039,-1033,-1027,-1021,-1015,-1010,-1004,-998,-992,-987,-981,-976,-970,-964,-959, - -953,-948,-942,-937,-931,-926,-920,-915,-910,-904,-899,-894,-888,-883,-878,-873, - -868,-862,-857,-852,-847,-842,-837,-832,-827,-822,-817,-812,-807,-802,-797,-792, - -787,-782,-777,-772,-768,-763,-758,-753,-748,-744,-739,-734,-729,-725,-720,-715, - -711,-706,-702,-697,-692,-688,-683,-679,-674,-670,-665,-661,-657,-652,-648,-643, - -639,-635,-630,-626,-622,-617,-613,-609,-605,-600,-596,-592,-588,-584,-579,-575, - -571,-567,-563,-559,-555,-551,-547,-543,-539,-535,-531,-527,-523,-519,-516,-512, - -508,-504,-500,-497,-493,-489,-485,-482,-478,-474,-471,-467,-463,-460,-456,-453, - -449,-446,-442,-439,-435,-432,-428,-425,-422,-418,-415,-412,-408,-405,-402,-399, - -395,-392,-389,-386,-383,-379,-376,-373,-370,-367,-364,-361,-358,-355,-352,-349, - -346,-343,-340,-338,-335,-332,-329,-326,-323,-321,-318,-315,-312,-310,-307,-304, - -302,-299,-296,-294,-291,-289,-286,-283,-281,-278,-276,-273,-271,-268,-266,-264, - -261,-259,-256,-254,-252,-249,-247,-245,-242,-240,-238,-236,-233,-231,-229,-227, - -224,-222,-220,-218,-216,-214,-212,-209,-207,-205,-203,-201,-199,-197,-195,-193, - -191,-189,-187,-185,-183,-181,-180,-178,-176,-174,-172,-170,-168,-166,-165,-163, - -161,-159,-157,-156,-154,-152,-151,-149,-147,-145,-144,-142,-140,-139,-137,-136, - -134,-132,-131,-129,-128,-126,-124,-123,-121,-120,-118,-117,-115,-114,-113,-111, - -110,-108,-107,-105,-104,-103,-101,-100,-99,-97,-96,-95,-93,-92,-91,-89,-88,-87,-86, - -84,-83,-82,-81,-80,-78,-77,-76,-75,-74,-73,-71,-70,-69,-68,-67,-66,-65,-64,-63, - -62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-46,-45,-44, - -43,-42,-41,-40,-40,-39,-38,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-30,-29,-28, - -27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-21,-20,-19,-19,-18,-18,-17,-16,-16,-15, - -15,-14,-14,-13,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-5,-4,-4,-3, - -3,-2,-2,-1,-1,-1,0,0,0,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,9, - 10,10,10,10,11,11,11,11,11,12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,15, - 15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16, - 16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14, - 14,14,14,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,10, - 10,10,10,10,10,10,9,9,9,9,9,9,8,8,8,8,8,8,8,7,7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,5,4, - 4,4,4,4,4,3,3,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0, - }, - { - 131072,131072,131072,131072,131072,131072,131072,131072,131071,131071,131071, - 131071,131071,131070,131070,131070,131069,131069,131068,131068,131067,131066,131066, - 131065,131064,131063,131061,131060,131058,131057,131055,131053,131051,131048,131046, - 131043,131040,131037,131033,131029,131025,131021,131016,131011,131005,130999,130993, - 130986,130978,130970,130962,130953,130943,130933,130922,130910,130897,130884,130870, - 130855,130839,130822,130804,130785,130765,130744,130721,130697,130672,130646,130618, - 130589,130558,130525,130491,130455,130417,130377,130336,130292,130246,130198,130147, - 130095,130039,129982,129921,129858,129792,129723,129651,129576,129497,129416,129330, - 129242,129149,129053,128953,128849,128741,128628,128512,128390,128265,128134,127998, - 127858,127712,127561,127405,127243,127076,126903,126723,126538,126346,126148,125944, - 125733,125515,125290,125058,124818,124572,124317,124055,123785,123508,123222,122927, - 122624,122313,121993,121664,121326,120978,120622,120255,119880,119494,119099,118693, - 118278,117852,117415,116968,116510,116042,115562,115072,114570,114057,113532,112996, - 112448,111889,111317,110734,110139,109532,108912,108280,107636,106980,106311,105630, - 104936,104229,103510,102778,102034,101276,100506,99724,98928,98120,97299,96466,95620, - 94761,93889,93005,92109,91200,90279,89345,88400,87442,86472,85490,84497,83492,82475, - 81447,80408,79358,78297,77225,76142,75050,73947,72834,71712,70580,69439,68289,67130, - 65963,64787,63604,62413,61215,60009,58797,57578,56354,55123,53887,52646,51401,50151, - 48897,47639,46378,45115,43848,42580,41310,40039,38767,37495,36223,34951,33680,32410, - 31142,29877,28614,27354,26098,24846,23598,22355,21118,19887,18662,17444,16233,15030, - 13835,12649,11472,10304,9147,8001,6865,5741,4629,3529,2442,1368,308,-738,-1769,-2786, - -3787,-4772,-5741,-6693,-7628,-8546,-9447,-10329,-11192,-12037,-12863,-13669,-14455, - -15221,-15967,-16692,-17396,-18079,-18741,-19380,-19998,-20593,-21167,-21717,-22245, - -22750,-23232,-23690,-24126,-24538,-24926,-25291,-25632,-25949,-26243,-26513,-26759, - -26981,-27179,-27354,-27505,-27633,-27737,-27818,-27875,-27910,-27921,-27909,-27875, - -27818,-27739,-27638,-27516,-27371,-27206,-27019,-26812,-26584,-26336,-26069,-25782, - -25476,-25151,-24808,-24448,-24070,-23674,-23263,-22835,-22391,-21933,-21459,-20972, - -20470,-19955,-19428,-18888,-18337,-17775,-17202,-16619,-16027,-15425,-14816,-14199, - -13574,-12943,-12306,-11663,-11016,-10364,-9709,-9051,-8390,-7728,-7064,-6400,-5735, - -5071,-4408,-3747,-3088,-2432,-1779,-1131,-486,153,786,1413,2034,2647,3253,3850,4439, - 5018,5587,6147,6696,7233,7759,8274,8776,9265,9741,10204,10652,11087,11507,11912, - 12303,12677,13037,13380,13707,14018,14313,14590,14851,15095,15321,15531,15723,15897, - 16055,16194,16316,16420,16507,16577,16628,16663,16679,16679,16661,16627,16575,16507, - 16422,16320,16203,16069,15920,15755,15575,15380,15170,14946,14708,14456,14191,13913, - 13622,13319,13004,12678,12340,11992,11633,11265,10887,10501,10106,9703,9292,8875, - 8451,8021,7585,7145,6699,6250,5797,5341,4883,4422,3960,3497,3033,2570,2106,1644, - 1183,724,268,-186,-636,-1082,-1524,-1961,-2393,-2820,-3240,-3654,-4061,-4460,-4852, - -5236,-5611,-5977,-6334,-6682,-7019,-7347,-7664,-7970,-8265,-8549,-8822,-9082,-9331, - -9567,-9791,-10002,-10200,-10386,-10558,-10718,-10864,-10997,-11116,-11222,-11314, - -11393,-11458,-11510,-11548,-11573,-11584,-11582,-11566,-11537,-11496,-11441,-11373, - -11293,-11200,-11095,-10978,-10849,-10708,-10556,-10392,-10218,-10032,-9837,-9631, - -9415,-9190,-8955,-8712,-8460,-8200,-7931,-7656,-7373,-7083,-6787,-6485,-6177,-5864, - -5547,-5224,-4898,-4568,-4235,-3899,-3560,-3220,-2878,-2535,-2191,-1847,-1502,-1158, - -816,-474,-134,204,540,872,1202,1528,1849,2167,2480,2788,3091,3388,3678,3963,4241, - 4512,4776,5033,5281,5522,5754,5979,6194,6400,6598,6786,6965,7134,7293,7443,7582, - 7711,7830,7939,8038,8126,8203,8271,8327,8373,8409,8434,8448,8452,8446,8429,8403, - 8366,8319,8262,8195,8119,8033,7938,7834,7721,7599,7469,7330,7183,7028,6865,6695, - 6518,6334,6143,5946,5743,5534,5319,5100,4875,4646,4412,4175,3934,3689,3442,3192, - 2940,2685,2429,2172,1913,1654,1394,1135,875,616,359,102,-153,-406,-657,-906,-1152, - -1394,-1634,-1870,-2101,-2329,-2552,-2771,-2985,-3193,-3396,-3594,-3785,-3971,-4150, - -4323,-4490,-4649,-4802,-4947,-5086,-5217,-5340,-5456,-5564,-5665,-5757,-5842,-5919, - -5987,-6048,-6101,-6145,-6181,-6209,-6229,-6241,-6245,-6241,-6229,-6210,-6182,-6147, - -6104,-6053,-5996,-5930,-5858,-5779,-5693,-5600,-5501,-5395,-5283,-5165,-5041,-4911, - -4777,-4637,-4491,-4341,-4187,-4028,-3865,-3699,-3528,-3354,-3177,-2998,-2815,-2630, - -2444,-2255,-2064,-1872,-1680,-1486,-1292,-1097,-902,-708,-513,-320,-127,64,254,442, - 629,813,995,1174,1351,1525,1695,1862,2026,2185,2341,2493,2640,2783,2921,3054,3183, - 3306,3424,3537,3645,3746,3843,3933,4018,4097,4170,4237,4298,4353,4402,4445,4482, - 4512,4536,4555,4567,4573,4573,4566,4554,4537,4513,4483,4448,4407,4361,4309,4252, - 4190,4122,4050,3973,3891,3805,3714,3619,3520,3417,3310,3200,3086,2969,2849,2726, - 2600,2472,2341,2209,2074,1938,1800,1660,1520,1378,1236,1093,950,806,663,520,377,235, - 93,-48,-187,-325,-462,-597,-730,-862,-991,-1118,-1242,-1364,-1483,-1599,-1712, - -1822,-1929,-2032,-2132,-2228,-2320,-2409,-2494,-2575,-2651,-2724,-2792,-2856,-2916, - -2971,-3022,-3069,-3111,-3148,-3181,-3210,-3234,-3253,-3268,-3278,-3284,-3285,-3282, - -3275,-3263,-3247,-3227,-3202,-3174,-3141,-3104,-3064,-3019,-2971,-2919,-2864,-2805, - -2743,-2678,-2610,-2539,-2464,-2387,-2308,-2226,-2142,-2055,-1966,-1876,-1783,-1689, - -1594,-1497,-1399,-1299,-1199,-1098,-996,-894,-791,-689,-586,-483,-380,-278,-176,-75, - 26,126,224,322,418,513,606,698,788,877,963,1047,1129,1209,1287,1362,1434,1504, - 1572,1637,1698,1757,1814,1867,1917,1964,2008,2049,2086,2121,2152,2180,2205,2227, - 2245,2260,2272,2280,2286,2288,2287,2283,2276,2265,2252,2236,2216,2194,2169,2142, - 2111,2078,2042,2004,1963,1921,1875,1828,1778,1727,1673,1618,1561,1502,1442,1380, - 1317,1253,1187,1120,1053,984,915,846,775,705,633,562,491,419,348,277,206,135,65,-5, - -74,-142,-209,-276,-341,-406,-469,-531,-592,-651,-709,-765,-820,-873,-924,-974, - -1021,-1067,-1111,-1153,-1193,-1231,-1267,-1301,-1332,-1362,-1389,-1414,-1437,-1457, - -1476,-1492,-1505,-1517,-1526,-1534,-1538,-1541,-1542,-1540,-1536,-1530,-1522,-1512, - -1500,-1486,-1470,-1452,-1432,-1410,-1387,-1362,-1335,-1306,-1276,-1245,-1212,-1178, - -1142,-1105,-1067,-1028,-987,-946,-904,-861,-817,-772,-727,-681,-635,-588,-541,-494, - -446,-399,-351,-303,-255,-208,-160,-113,-66,-20,26,72,117,161,205,248,290,331,371, - 411,449,486,523,558,592,624,656,686,715,743,769,794,817,839,860,879,897,913,928, - 941,953,963,972,979,985,989,992,993,993,992,989,984,979,972,963,954,943,931,917, - 903,887,870,852,833,813,792,771,748,724,700,675,649,623,596,568,540,512,483,453, - 424,394,363,333,302,272,241,210,180,149,119,88,58,28,-1,-30,-59,-88,-115,-143,-170, - -196,-222,-247,-272,-296,-319,-341,-363,-384,-404,-423,-441,-459,-476,-491,-506, - -520,-533,-545,-557,-567,-576,-584,-592,-598,-604,-608,-612,-614,-616,-617,-616, - -615,-613,-610,-607,-602,-597,-591,-583,-576,-567,-558,-548,-537,-526,-514,-501, - -488,-474,-460,-445,-430,-414,-398,-382,-365,-347,-330,-312,-294,-276,-257,-239, - -220,-201,-182,-163,-144,-126,-107,-88,-69,-51,-32,-14,4,22,39,56,73,90,106,122,137, - 152,167,181,195,208,221,233,245,257,267,277,287,296,305,313,320,327,333,339,344, - 348,352,355,358,360,362,363,363,363,362,361,359,357,354,351,347,343,338,333,327, - 321,315,308,301,293,285,277,268,259,250,241,231,221,211,201,190,180,169,158,147, - 136,125,114,103,91,80,69,58,47,36,25,15,4,-7,-17,-27,-37,-47,-56,-66,-75,-84,-92, - -101,-109,-117,-124,-131,-138,-145,-151,-157,-163,-168,-173,-178,-182,-186,-189, - -193,-196,-198,-200,-202,-204,-205,-206,-206,-206,-206,-206,-205,-204,-203,-201, - -199,-197,-194,-191,-188,-185,-181,-178,-174,-169,-165,-160,-155,-150,-145,-140, - -135,-129,-123,-117,-111,-105,-99,-93,-87,-81,-74,-68,-62,-55,-49,-43,-36,-30,-24, - -18,-12,-6,0,6,12,18,23,29,34,39,44,49,54,58,63,67,71,75,79,82,86,89,92,95,97,100, - 102,104,106,107,109,110,111,112,112,113,113,113,113,113,112,112,111,110,109,107, - 106,104,103,101,99,97,94,92,89,87,84,81,78,75,72,69,66,63,60,56,53,50,46,43,39,36, - 32,29,25,22,18,15,12,8,5,2,-1,-5,-8,-11,-14,-17,-19,-22,-25,-27,-30,-32,-35,-37, - -39,-41,-43,-45,-46,-48,-50,-51,-52,-53,-54,-55,-56,-57,-58,-58,-59,-59,-59,-59, - -59,-59,-59,-59,-58,-58,-57,-57,-56,-55,-54,-54,-53,-51,-50,-49,-48,-46,-45,-44, - -42,-41,-39,-37,-36,-34,-32,-31,-29,-27,-25,-23,-22,-20,-18,-16,-14,-12,-11,-9,-7, - -5,-4,-2,0,1,3,5,6,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,25,26,27,27,28, - 28,29,29,29,29,29,30,30,30,30,29,29,29,29,29,28,28,27,27,27,26,25,25,24,24,23,22, - 21,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,7,6,5,4,3,2,1,0,0,-1,-2,-3,-3,-4, - -5,-6,-6,-7,-7,-8,-9,-9,-10,-10,-11,-11,-11,-12,-12,-12,-13,-13,-13,-13,-14,-14, - -14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-13,-13,-13,-13,-13,-12,-12,-12,-11, - -11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-7,-7,-6,-6,-6,-5,-5,-4,-4,-3,-3,-3,-2,-2,-1,-1, - -1,0,0,1,1,1,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,5,5,5,5,5,5,5,4,4,4,4,4,4,3,3,3,3,3,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,-1, - -1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-3,-3,-3,-3,-3,-3, - -3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - }, -}; +/* + * Table generated by contrib/sinc-integral.py. + */ + +/* tables are: a500 off, a500 on, a1200 off, a1200 on, vanilla. */ +const int winsinc_integral[5][SINC_QUEUE_MAX_AGE] = +{ + { + 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, + 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131070, + 131070,131070,131070,131070,131069,131069,131069,131069,131068,131068,131067,131067, + 131066,131066,131065,131065,131064,131063,131062,131062,131061,131060,131058,131057, + 131056,131055,131053,131051,131050,131048,131046,131043,131041,131039,131036,131033, + 131030,131027,131023,131019,131016,131011,131007,131002,130997,130992,130986,130980, + 130973,130967,130959,130952,130944,130935,130926,130917,130907,130896,130885,130873, + 130861,130848,130835,130820,130805,130789,130773,130756,130737,130718,130698,130677, + 130655,130633,130609,130584,130557,130530,130502,130472,130441,130408,130375,130339, + 130303,130265,130225,130184,130141,130096,130050,130002,129952,129900,129846,129790, + 129732,129672,129609,129545,129478,129409,129337,129263,129186,129107,129025,128940, + 128852,128762,128669,128572,128473,128370,128264,128155,128043,127927,127807,127684, + 127558,127428,127293,127156,127014,126868,126718,126564,126406,126243,126076,125905, + 125729,125549,125364,125174,124980,124780,124576,124367,124152,123933,123708,123478, + 123243,123002,122756,122505,122247,121985,121716,121442,121162,120876,120584,120286, + 119982,119672,119356,119033,118705,118370,118029,117682,117328,116967,116601,116228, + 115848,115462,115069,114670,114264,113851,113432,113006,112573,112134,111688,111236, + 110777,110311,109838,109359,108874,108381,107882,107377,106865,106346,105821,105290, + 104752,104208,103657,103100,102537,101968,101392,100811,100224,99630,99031,98426, + 97816,97199,96578,95950,95318,94680,94037,93389,92736,92079,91416,90749,90077,89401, + 88721,88037,87348,86656,85960,85260,84557,83851,83141,82429,81713,80995,80274,79551, + 78826,78098,77369,76638,75905,75171,74435,73699,72961,72223,71484,70745,70006,69266, + 68527,67788,67050,66312,65576,64840,64106,63373,62641,61912,61184,60459,59736,59015, + 58297,57582,56871,56162,55457,54755,54058,53364,52674,51989,51308,50632,49960,49294, + 48632,47976,47325,46680,46041,45407,44780,44158,43543,42934,42332,41737,41148,40566, + 39991,39424,38863,38310,37765,37227,36696,36173,35659,35152,34652,34161,33678,33204, + 32737,32279,31828,31387,30953,30528,30112,29704,29304,28913,28530,28155,27790,27432, + 27083,26743,26411,26087,25772,25465,25166,24875,24593,24318,24052,23794,23543,23300, + 23066,22838,22619,22406,22202,22004,21814,21631,21454,21285,21122,20966,20816,20673, + 20536,20404,20279,20160,20046,19938,19835,19738,19645,19558,19475,19396,19322,19253, + 19187,19126,19068,19014,18963,18915,18871,18830,18791,18755,18721,18690,18661,18633, + 18608,18584,18561,18540,18520,18501,18483,18465,18448,18431,18414,18398,18381,18364, + 18347,18329,18310,18291,18270,18249,18226,18203,18177,18150,18122,18092,18060,18026, + 17990,17951,17911,17868,17823,17775,17725,17672,17617,17559,17498,17434,17368,17298, + 17226,17150,17072,16990,16906,16818,16727,16634,16537,16437,16334,16228,16119,16007, + 15892,15774,15653,15529,15403,15273,15141,15006,14868,14728,14585,14440,14293,14143, + 13990,13836,13680,13521,13361,13198,13035,12869,12702,12533,12363,12192,12019,11846, + 11671,11496,11320,11143,10966,10789,10611,10433,10255,10076,9898,9721,9543,9367,9190, + 9015,8840,8666,8493,8322,8151,7982,7814,7648,7484,7321,7160,7002,6845,6690,6537, + 6387,6239,6094,5951,5811,5673,5538,5406,5277,5151,5027,4907,4790,4676,4565,4458, + 4354,4253,4155,4061,3970,3882,3798,3718,3640,3567,3496,3430,3366,3306,3250,3197, + 3147,3100,3057,3018,2981,2948,2918,2892,2868,2847,2830,2815,2804,2795,2789,2786, + 2785,2787,2792,2799,2809,2820,2834,2851,2869,2889,2911,2935,2961,2988,3017,3048, + 3079,3113,3147,3182,3218,3256,3294,3332,3372,3412,3452,3493,3534,3575,3616,3657, + 3698,3739,3780,3820,3860,3899,3937,3975,4012,4048,4083,4118,4151,4183,4213,4243, + 4271,4297,4323,4346,4368,4389,4407,4424,4440,4453,4465,4474,4482,4488,4492,4494, + 4494,4491,4487,4481,4472,4462,4449,4435,4418,4399,4378,4355,4330,4303,4274,4243, + 4210,4176,4139,4100,4060,4017,3973,3927,3880,3831,3780,3728,3674,3619,3562,3504, + 3445,3384,3323,3260,3196,3132,3066,2999,2932,2864,2796,2727,2657,2587,2516,2446, + 2375,2304,2232,2161,2090,2019,1948,1878,1807,1738,1668,1599,1531,1464,1397,1331, + 1266,1201,1138,1076,1015,954,896,838,782,726,673,620,570,520,473,426,382,339,297, + 258,220,184,149,116,86,56,29,4,-20,-42,-62,-80,-96,-111,-123,-134,-143,-151,-156, + -160,-162,-162,-161,-158,-153,-147,-139,-130,-119,-107,-93,-78,-61,-43,-24,-4,17,40, + 64,89,114,141,168,197,226,256,286,318,349,381,414,447,481,514,548,582,616,651,685, + 719,753,787,821,854,887,920,953,985,1016,1047,1077,1107,1136,1164,1192,1218,1244, + 1269,1293,1316,1338,1359,1379,1398,1416,1433,1449,1463,1477,1489,1500,1509,1518, + 1525,1531,1536,1539,1541,1542,1542,1541,1538,1534,1528,1522,1514,1505,1495,1483, + 1471,1457,1442,1426,1409,1391,1372,1352,1331,1309,1286,1262,1238,1212,1186,1159, + 1131,1102,1073,1044,1013,983,951,919,887,855,822,789,755,722,688,654,620,586,552, + 518,484,451,417,384,351,318,285,253,221,190,159,129,99,69,41,12,-15,-42,-68,-93, + -118,-142,-165,-187,-209,-229,-249,-268,-285,-302,-318,-333,-347,-361,-373,-384, + -394,-403,-412,-419,-425,-430,-435,-438,-440,-442,-442,-442,-440,-438,-435,-431, + -426,-420,-413,-405,-397,-388,-378,-367,-356,-344,-331,-318,-304,-289,-274,-258, + -242,-225,-208,-191,-173,-154,-136,-117,-97,-78,-58,-38,-18,2,22,43,63,83,104,124, + 144,164,184,204,223,243,262,281,299,317,335,352,369,386,402,418,433,448,462,475, + 488,501,513,524,535,545,554,563,571,579,586,592,597,602,606,610,612,615,616,617, + 617,616,615,613,610,607,603,599,593,588,581,574,567,559,550,541,532,521,511,500, + 488,476,464,451,438,424,411,397,382,368,353,338,322,307,291,275,259,243,227,211, + 195,179,163,147,130,115,99,83,67,52,37,21,7,-8,-22,-36,-50,-64,-77,-90,-103,-115, + -127,-138,-149,-160,-170,-180,-189,-198,-207,-215,-222,-229,-236,-242,-248,-253, + -258,-262,-266,-269,-272,-274,-276,-277,-278,-278,-278,-278,-277,-275,-273,-271, + -268,-265,-262,-258,-253,-248,-243,-238,-232,-226,-219,-212,-205,-198,-190,-182, + -174,-166,-157,-148,-139,-130,-121,-112,-102,-92,-83,-73,-63,-53,-43,-33,-23,-13,-3, + 7,17,27,36,46,55,65,74,83,92,101,109,118,126,134,141,149,156,163,170,177,183,189, + 194,200,205,210,214,218,222,226,229,232,234,237,239,240,241,242,243,243,244,243, + 243,242,241,239,237,235,233,230,227,224,221,217,213,209,205,200,196,191,186,180, + 175,169,163,157,151,145,139,132,126,119,113,106,99,92,85,79,72,65,58,51,44,37,31, + 24,17,11,4,-2,-9,-15,-21,-27,-33,-39,-44,-50,-55,-60,-65,-70,-74,-79,-83,-87,-91, + -95,-98,-102,-105,-108,-110,-113,-115,-117,-119,-121,-122,-123,-124,-125,-126,-126, + -126,-126,-126,-126,-125,-124,-123,-122,-121,-119,-118,-116,-114,-112,-110,-107, + -105,-102,-99,-96,-93,-90,-86,-83,-80,-76,-72,-69,-65,-61,-57,-53,-49,-45,-41,-37, + -33,-29,-25,-21,-17,-13,-8,-4,0,3,7,11,15,19,22,26,30,33,36,40,43,46,49,52,55,57, + 60,62,65,67,69,71,73,74,76,78,79,80,81,82,83,84,84,85,85,85,85,85,85,85,85,84,83, + 83,82,81,80,79,77,76,75,73,72,70,68,66,64,62,60,58,56,54,52,49,47,45,42,40,37,35, + 32,30,27,25,22,20,17,15,12,10,8,5,3,0,-2,-4,-6,-9,-11,-13,-15,-17,-19,-21,-22,-24, + -26,-27,-29,-30,-32,-33,-34,-35,-37,-38,-39,-39,-40,-41,-42,-42,-43,-43,-43,-44, + -44,-44,-44,-44,-44,-44,-44,-43,-43,-42,-42,-41,-41,-40,-39,-39,-38,-37,-36,-35, + -34,-33,-32,-31,-29,-28,-27,-26,-24,-23,-22,-20,-19,-18,-16,-15,-14,-12,-11,-9,-8, + -6,-5,-4,-2,-1,0,2,3,4,6,7,8,9,10,12,13,14,15,16,17,18,18,19,20,21,22,22,23,23,24, + 24,25,25,26,26,26,27,27,27,27,27,27,27,27,27,27,27,26,26,26,25,25,25,24,24,23,23, + 22,22,21,21,20,19,19,18,17,16,16,15,14,13,13,12,11,10,9,9,8,7,6,5,5,4,3,2,2,1,0, + -1,-1,-2,-3,-3,-4,-5,-5,-6,-6,-7,-8,-8,-9,-9,-9,-10,-10,-11,-11,-11,-12,-12,-12, + -12,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-12,-12, + -12,-12,-11,-11,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-8,-7,-7,-6,-6,-5,-5,-5,-4,-4, + -3,-3,-3,-2,-2,-1,-1,-1,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,4,4,4,4,4,3,3,3,3,3, + 2,2,2,2,2,1,1,1,1,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-3,-3,-3, + -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3, + -3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0, + 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, + 131072,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, + 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, + 131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131070, + 131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131069,131069, + 131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,131069, + 131069,131068,131068,131068,131068,131068,131068,131068,131068,131068,131068,131067, + 131067,131067,131067,131067,131067,131067,131066,131066,131066,131066,131066,131065, + 131065,131065,131065,131064,131064,131064,131064,131063,131063,131062,131062,131062, + 131061,131061,131060,131060,131059,131059,131058,131058,131057,131056,131056,131055, + 131054,131053,131052,131052,131051,131050,131049,131048,131046,131045,131044,131043, + 131041,131040,131038,131037,131035,131034,131032,131030,131028,131026,131024,131022, + 131020,131017,131015,131012,131010,131007,131004,131001,130998,130994,130991,130987, + 130984,130980,130976,130972,130968,130963,130959,130954,130949,130944,130938,130933, + 130927,130921,130915,130909,130902,130895,130888,130881,130873,130865,130857,130849, + 130840,130831,130822,130813,130803,130793,130782,130771,130760,130749,130737,130725, + 130712,130699,130685,130672,130657,130643,130628,130612,130596,130580,130563,130545, + 130528,130509,130490,130471,130451,130430,130409,130388,130365,130343,130319,130295, + 130270,130245,130219,130193,130165,130137,130109,130079,130049,130018,129987,129954, + 129921,129887,129853,129817,129781,129744,129706,129667,129627,129587,129545,129503, + 129459,129415,129370,129324,129276,129228,129179,129129,129078,129026,128972,128918, + 128862,128806,128748,128690,128630,128569,128507,128443,128379,128313,128246,128178, + 128109,128038,127966,127893,127819,127743,127667,127588,127509,127428,127346,127262, + 127177,127091,127004,126915,126824,126732,126639,126545,126449,126351,126252,126152, + 126050,125947,125842,125736,125628,125519,125408,125296,125182,125067,124950,124832, + 124712,124591,124468,124344,124218,124090,123961,123830,123698,123564,123429,123292, + 123154,123014,122872,122729,122585,122438,122291,122141,121990,121838,121684,121528, + 121371,121212,121052,120891,120727,120562,120396,120228,120059,119888,119715,119541, + 119366,119189,119011,118831,118649,118467,118282,118097,117909,117721,117531,117339, + 117146,116952,116757,116560,116361,116161,115960,115758,115554,115349,115143,114935, + 114726,114516,114305,114092,113878,113663,113447,113229,113011,112791,112570,112348, + 112124,111900,111675,111448,111220,110992,110762,110531,110300,110067,109833,109598, + 109363,109126,108889,108650,108411,108171,107930,107688,107445,107201,106957,106712, + 106466,106219,105972,105723,105474,105225,104974,104723,104471,104219,103966,103712, + 103458,103203,102948,102692,102435,102178,101920,101662,101403,101144,100885,100624, + 100364,100103,99841,99579,99317,99054,98791,98527,98264,97999,97735,97470,97204,96939, + 96673,96407,96140,95873,95606,95339,95071,94804,94536,94267,93999,93730,93461,93192, + 92923,92653,92383,92114,91844,91573,91303,91033,90762,90491,90220,89949,89678,89407, + 89136,88865,88593,88321,88050,87778,87506,87234,86962,86690,86418,86146,85874,85602, + 85330,85057,84785,84513,84240,83968,83696,83423,83151,82878,82606,82333,82061,81789, + 81516,81244,80971,80699,80427,80154,79882,79610,79337,79065,78793,78521,78249,77977, + 77705,77433,77161,76889,76617,76345,76074,75802,75531,75259,74988,74717,74446,74175, + 73904,73633,73362,73092,72821,72551,72280,72010,71740,71470,71201,70931,70661,70392, + 70123,69854,69585,69317,69048,68780,68512,68244,67976,67709,67441,67174,66907,66641, + 66374,66108,65842,65576,65311,65046,64781,64516,64252,63988,63724,63460,63197,62934, + 62672,62409,62147,61886,61624,61363,61103,60843,60583,60323,60064,59805,59547,59289, + 59031,58774,58517,58261,58005,57749,57494,57239,56985,56731,56478,56225,55973,55721, + 55470,55219,54968,54718,54469,54220,53971,53724,53476,53229,52983,52737,52492,52247, + 52003,51759,51516,51274,51032,50791,50550,50310,50070,49831,49593,49355,49118,48881, + 48645,48410,48175,47941,47707,47474,47242,47010,46779,46549,46319,46090,45861,45633, + 45406,45179,44953,44728,44503,44279,44056,43833,43611,43389,43168,42948,42728,42510, + 42291,42074,41857,41640,41425,41210,40995,40782,40568,40356,40144,39933,39723,39513, + 39304,39095,38887,38680,38473,38267,38062,37857,37653,37449,37247,37044,36843,36642, + 36442,36242,36043,35845,35647,35450,35253,35057,34862,34667,34473,34280,34087,33894, + 33703,33512,33321,33132,32942,32754,32566,32378,32192,32006,31820,31635,31451,31267, + 31084,30901,30719,30538,30357,30177,29997,29818,29640,29462,29285,29108,28932,28756, + 28581,28407,28233,28060,27888,27716,27545,27374,27204,27034,26865,26697,26529,26362, + 26195,26029,25863,25699,25534,25371,25207,25045,24883,24722,24561,24401,24241,24082, + 23924,23766,23609,23453,23297,23142,22987,22833,22679,22526,22374,22222,22071,21921, + 21771,21622,21473,21325,21177,21031,20884,20739,20594,20449,20306,20162,20020,19878, + 19737,19596,19456,19316,19178,19039,18902,18765,18628,18493,18358,18223,18089,17956, + 17823,17691,17560,17429,17299,17169,17040,16912,16784,16657,16531,16405,16280,16155, + 16031,15908,15785,15663,15541,15420,15300,15180,15061,14942,14824,14707,14590,14474, + 14358,14243,14129,14015,13901,13789,13677,13565,13454,13344,13234,13125,13016,12908, + 12801,12694,12588,12482,12377,12272,12168,12064,11961,11859,11757,11655,11554,11454, + 11354,11255,11156,11058,10960,10863,10766,10670,10575,10480,10385,10291,10197,10104, + 10012,9920,9828,9737,9646,9556,9466,9377,9289,9200,9113,9025,8939,8852,8766,8681, + 8596,8512,8428,8344,8261,8178,8096,8014,7933,7852,7772,7692,7612,7533,7455,7376, + 7299,7221,7144,7068,6992,6916,6841,6766,6692,6618,6544,6471,6398,6326,6254,6182, + 6111,6041,5970,5901,5831,5762,5693,5625,5557,5490,5423,5356,5290,5224,5159,5093, + 5029,4965,4901,4837,4774,4711,4649,4587,4525,4464,4404,4343,4283,4224,4164,4105, + 4047,3989,3931,3874,3817,3760,3704,3648,3593,3538,3483,3429,3375,3321,3268,3215, + 3163,3111,3059,3008,2957,2906,2856,2806,2756,2707,2658,2610,2562,2514,2466,2419, + 2373,2326,2280,2235,2189,2144,2100,2056,2012,1968,1925,1882,1839,1797,1755,1714, + 1672,1631,1591,1551,1511,1471,1432,1393,1354,1316,1278,1240,1203,1165,1129,1092, + 1056,1020,984,949,914,879,845,811,777,743,710,677,644,612,580,548,516,485,454,423, + 393,362,332,303,273,244,215,186,158,129,101,74,46,19,-8,-35,-61,-88,-114,-140,-165, + -191,-216,-241,-265,-290,-314,-338,-362,-386,-409,-432,-455,-478,-501,-523,-545, + -567,-589,-610,-632,-653,-674,-694,-715,-735,-756,-775,-795,-815,-834,-853,-872, + -891,-910,-928,-947,-965,-983,-1000,-1018,-1035,-1052,-1069,-1086,-1103,-1119,-1136, + -1152,-1168,-1184,-1199,-1215,-1230,-1245,-1260,-1275,-1289,-1304,-1318,-1332,-1346, + -1360,-1373,-1387,-1400,-1413,-1426,-1439,-1452,-1464,-1477,-1489,-1501,-1513,-1524, + -1536,-1547,-1558,-1570,-1581,-1591,-1602,-1612,-1623,-1633,-1643,-1653,-1663,-1672, + -1682,-1691,-1700,-1709,-1718,-1727,-1735,-1744,-1752,-1760,-1768,-1776,-1784,-1792, + -1799,-1807,-1814,-1821,-1828,-1835,-1842,-1848,-1855,-1861,-1867,-1873,-1879,-1885, + -1891,-1896,-1902,-1907,-1913,-1918,-1923,-1928,-1932,-1937,-1942,-1946,-1950,-1955, + -1959,-1963,-1967,-1971,-1974,-1978,-1981,-1985,-1988,-1991,-1994,-1997,-2000,-2003, + -2006,-2009,-2011,-2013,-2016,-2018,-2020,-2022,-2024,-2026,-2028,-2030,-2032,-2033, + -2035,-2036,-2037,-2039,-2040,-2041,-2042,-2043,-2044,-2045,-2045,-2046,-2047,-2047, + -2048,-2048,-2048,-2049,-2049,-2049,-2049,-2049,-2049,-2049,-2049,-2048,-2048,-2048, + -2047,-2047,-2046,-2046,-2045,-2044,-2043,-2043,-2042,-2041,-2040,-2039,-2038,-2036, + -2035,-2034,-2033,-2031,-2030,-2028,-2027,-2025,-2024,-2022,-2020,-2019,-2017,-2015, + -2013,-2011,-2009,-2007,-2005,-2003,-2001,-1998,-1996,-1994,-1992,-1989,-1987,-1984, + -1982,-1979,-1977,-1974,-1971,-1969,-1966,-1963,-1960,-1957,-1954,-1952,-1949,-1946, + -1942,-1939,-1936,-1933,-1930,-1927,-1923,-1920,-1917,-1913,-1910,-1906,-1903,-1899, + -1896,-1892,-1889,-1885,-1881,-1878,-1874,-1870,-1866,-1863,-1859,-1855,-1851,-1847, + -1843,-1839,-1835,-1831,-1827,-1823,-1819,-1814,-1810,-1806,-1802,-1798,-1793,-1789, + -1785,-1780,-1776,-1771,-1767,-1763,-1758,-1754,-1749,-1745,-1740,-1736,-1731,-1726, + -1722,-1717,-1713,-1708,-1703,-1698,-1694,-1689,-1684,-1680,-1675,-1670,-1665,-1660, + -1656,-1651,-1646,-1641,-1636,-1631,-1626,-1622,-1617,-1612,-1607,-1602,-1597,-1592, + -1587,-1582,-1577,-1572,-1567,-1562,-1557,-1552,-1547,-1542,-1537,-1532,-1527,-1522, + -1517,-1512,-1507,-1502,-1497,-1492,-1487,-1482,-1477,-1471,-1466,-1461,-1456,-1451, + -1446,-1441,-1436,-1431,-1426,-1421,-1416,-1411,-1406,-1401,-1395,-1390,-1385,-1380, + -1375,-1370,-1365,-1360,-1355,-1350,-1345,-1340,-1335,-1330,-1325,-1320,-1315,-1310, + -1305,-1300,-1295,-1290,-1285,-1280,-1275,-1270,-1265,-1260,-1255,-1250,-1245,-1240, + -1235,-1230,-1225,-1220,-1215,-1210,-1205,-1200,-1195,-1190,-1185,-1180,-1175,-1171, + -1166,-1161,-1156,-1151,-1146,-1141,-1136,-1131,-1127,-1122,-1117,-1112,-1107,-1102, + -1098,-1093,-1088,-1083,-1078,-1074,-1069,-1064,-1059,-1055,-1050,-1045,-1040,-1036, + -1031,-1026,-1022,-1017,-1012,-1007,-1003,-998,-994,-989,-984,-980,-975,-970,-966, + -961,-957,-952,-948,-943,-938,-934,-929,-925,-920,-916,-911,-907,-902,-898,-894, + -889,-885,-880,-876,-872,-867,-863,-858,-854,-850,-845,-841,-837,-833,-828,-824, + -820,-816,-811,-807,-803,-799,-795,-790,-786,-782,-778,-774,-770,-766,-762,-757, + -753,-749,-745,-741,-737,-733,-729,-725,-721,-717,-714,-710,-706,-702,-698,-694, + -690,-686,-683,-679,-675,-671,-667,-664,-660,-656,-652,-649,-645,-641,-638,-634, + -630,-627,-623,-620,-616,-612,-609,-605,-602,-598,-595,-591,-588,-584,-581,-577, + -574,-571,-567,-564,-560,-557,-554,-550,-547,-544,-540,-537,-534,-530,-527,-524, + -521,-518,-514,-511,-508,-505,-502,-499,-495,-492,-489,-486,-483,-480,-477,-474, + -471,-468,-465,-462,-459,-456,-453,-450,-447,-444,-441,-438,-435,-433,-430,-427, + -424,-421,-418,-416,-413,-410,-407,-405,-402,-399,-396,-394,-391,-388,-386,-383, + -380,-378,-375,-373,-370,-367,-365,-362,-360,-357,-355,-352,-350,-347,-345,-342, + -340,-337,-335,-333,-330,-328,-325,-323,-321,-318,-316,-314,-311,-309,-307,-305, + -302,-300,-298,-296,-293,-291,-289,-287,-285,-282,-280,-278,-276,-274,-272,-270, + -268,-266,-264,-261,-259,-257,-255,-253,-251,-249,-247,-246,-244,-242,-240,-238, + -236,-234,-232,-230,-228,-227,-225,-223,-221,-219,-217,-216,-214,-212,-210,-209, + -207,-205,-203,-202,-200,-198,-197,-195,-193,-192,-190,-188,-187,-185,-184,-182, + -180,-179,-177,-176,-174,-173,-171,-170,-168,-167,-165,-164,-162,-161,-159,-158, + -156,-155,-154,-152,-151,-149,-148,-147,-145,-144,-143,-141,-140,-139,-137,-136, + -135,-133,-132,-131,-130,-128,-127,-126,-125,-123,-122,-121,-120,-119,-117,-116, + -115,-114,-113,-112,-111,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98, + -97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78, + -78,-77,-76,-75,-74,-73,-72,-71,-71,-70,-69,-68,-67,-67,-66,-65,-64,-63,-63,-62, + -61,-60,-60,-59,-58,-58,-57,-56,-55,-55,-54,-53,-53,-52,-51,-51,-50,-49,-49,-48, + -47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36, + -36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-28,-27,-27, + -26,-26,-25,-25,-25,-24,-24,-23,-23,-23,-22,-22,-21,-21,-21,-20,-20,-20,-19,-19, + -19,-18,-18,-17,-17,-17,-17,-16,-16,-16,-15,-15,-15,-14,-14,-14,-13,-13,-13,-13, + -12,-12,-12,-12,-11,-11,-11,-11,-10,-10,-10,-10,-9,-9,-9,-9,-9,-8,-8,-8,-8,-7,-7, + -7,-7,-7,-7,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,-4,-4,-3,-3,-3,-3, + -3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, + 131072,131072,131072,131071,131071,131071,131071,131071,131071,131070,131070,131070, + 131070,131069,131069,131069,131068,131068,131067,131066,131066,131065,131064,131063, + 131062,131061,131059,131058,131056,131055,131053,131051,131049,131046,131044,131041, + 131038,131035,131031,131028,131024,131019,131015,131010,131004,130998,130992,130986, + 130979,130971,130963,130955,130945,130936,130925,130914,130903,130890,130877,130863, + 130849,130833,130816,130799,130781,130761,130740,130719,130696,130672,130646,130619, + 130591,130562,130531,130498,130463,130427,130390,130350,130308,130265,130219,130172, + 130122,130069,130015,129958,129898,129836,129772,129704,129633,129560,129483,129404, + 129321,129235,129145,129051,128954,128854,128749,128640,128527,128410,128289,128163, + 128033,127898,127758,127613,127463,127308,127147,126982,126810,126633,126450,126261, + 126066,125864,125657,125443,125222,124994,124759,124518,124269,124013,123749,123478, + 123199,122912,122617,122314,122003,121683,121355,121017,120672,120317,119953,119579, + 119197,118805,118403,117992,117570,117139,116698,116246,115784,115312,114829,114336, + 113831,113316,112790,112253,111705,111145,110575,109992,109399,108794,108177,107549, + 106909,106257,105594,104918,104231,103532,102821,102098,101363,100616,99858,99087, + 98304,97510,96703,95885,95054,94212,93358,92493,91616,90727,89827,88915,87992,87058, + 86113,85157,84190,83212,82224,81225,80216,79196,78167,77128,76079,75021,73953,72877, + 71792,70698,69596,68485,67367,66241,65108,63967,62820,61666,60506,59339,58168,56990, + 55808,54621,53429,52234,51034,49832,48626,47417,46206,44994,43779,42563,41347,40130, + 38913,37696,36480,35265,34052,32841,31632,30426,29223,28023,26828,25637,24451,23270, + 22095,20926,19764,18609,17461,16321,15190,14067,12953,11849,10755,9671,8598,7537, + 6487,5449,4423,3410,2411,1425,453,-504,-1447,-2375,-3287,-4184,-5064,-5928,-6775, + -7605,-8417,-9212,-9989,-10747,-11487,-12208,-12910,-13592,-14255,-14898,-15521, + -16124,-16706,-17268,-17809,-18329,-18829,-19306,-19763,-20198,-20612,-21004,-21374, + -21723,-22050,-22355,-22639,-22900,-23140,-23358,-23555,-23729,-23883,-24014,-24124, + -24213,-24281,-24328,-24353,-24359,-24343,-24307,-24251,-24175,-24079,-23964,-23830, + -23677,-23505,-23314,-23106,-22879,-22636,-22375,-22097,-21804,-21494,-21168,-20827, + -20472,-20102,-19718,-19320,-18909,-18486,-18050,-17603,-17144,-16674,-16194,-15705, + -15205,-14697,-14181,-13657,-13125,-12587,-12042,-11491,-10936,-10375,-9810,-9242, + -8670,-8096,-7520,-6942,-6363,-5783,-5204,-4625,-4047,-3471,-2897,-2325,-1756,-1191, + -630,-74,477,1023,1563,2096,2623,3142,3654,4157,4652,5138,5614,6081,6537,6983,7418, + 7842,8255,8655,9044,9420,9783,10134,10471,10795,11105,11401,11684,11952,12205,12444, + 12669,12878,13073,13252,13417,13567,13701,13820,13924,14012,14086,14144,14187,14215, + 14228,14226,14209,14178,14132,14071,13996,13907,13805,13688,13558,13415,13259,13089, + 12908,12714,12508,12290,12061,11821,11570,11309,11038,10756,10466,10166,9858,9542, + 9218,8886,8547,8201,7850,7492,7129,6761,6388,6011,5631,5247,4860,4471,4080,3687, + 3294,2899,2504,2110,1716,1323,931,541,154,-231,-613,-991,-1365,-1736,-2101,-2462, + -2817,-3166,-3510,-3847,-4177,-4500,-4816,-5124,-5424,-5716,-5999,-6273,-6539,-6795, + -7042,-7279,-7506,-7722,-7929,-8125,-8310,-8485,-8649,-8802,-8943,-9074,-9193,-9300, + -9397,-9481,-9555,-9617,-9667,-9706,-9733,-9749,-9754,-9748,-9730,-9701,-9661,-9610, + -9548,-9476,-9393,-9300,-9196,-9083,-8960,-8827,-8685,-8534,-8373,-8204,-8027,-7842, + -7648,-7447,-7238,-7023,-6801,-6572,-6337,-6096,-5849,-5598,-5341,-5080,-4815,-4545, + -4273,-3997,-3718,-3436,-3153,-2867,-2581,-2293,-2004,-1715,-1425,-1136,-848,-560, + -274,11,293,574,852,1127,1399,1667,1932,2192,2448,2699,2946,3187,3423,3653,3877, + 4095,4306,4511,4709,4900,5084,5261,5430,5591,5744,5889,6026,6155,6276,6388,6492, + 6587,6673,6750,6819,6879,6931,6973,7007,7031,7047,7055,7053,7043,7024,6997,6962, + 6918,6866,6805,6737,6661,6577,6486,6387,6281,6168,6048,5922,5789,5650,5504,5353, + 5196,5034,4866,4694,4517,4336,4150,3960,3767,3571,3371,3168,2963,2755,2546,2334, + 2122,1907,1692,1477,1261,1044,828,612,397,183,-30,-241,-451,-659,-864,-1067,-1268, + -1465,-1659,-1850,-2037,-2221,-2400,-2575,-2746,-2912,-3073,-3230,-3381,-3527,-3667, + -3802,-3931,-4054,-4172,-4283,-4388,-4487,-4579,-4665,-4745,-4818,-4884,-4944,-4997, + -5043,-5082,-5115,-5141,-5160,-5173,-5179,-5178,-5171,-5157,-5136,-5110,-5076,-5037, + -4991,-4940,-4882,-4819,-4749,-4675,-4594,-4509,-4418,-4322,-4221,-4116,-4006,-3891, + -3772,-3650,-3523,-3393,-3259,-3123,-2983,-2840,-2694,-2546,-2396,-2244,-2090,-1934, + -1777,-1619,-1459,-1299,-1139,-978,-817,-655,-495,-334,-175,-16,141,298,452,605,757, + 906,1053,1197,1339,1478,1615,1748,1878,2004,2127,2247,2362,2474,2582,2685,2785, + 2880,2970,3056,3137,3214,3286,3353,3415,3473,3525,3572,3615,3652,3684,3711,3733, + 3750,3762,3769,3771,3768,3760,3747,3729,3707,3680,3648,3611,3570,3525,3476,3422, + 3364,3302,3236,3166,3093,3016,2936,2852,2766,2676,2583,2488,2390,2290,2187,2082, + 1976,1867,1757,1645,1532,1418,1303,1187,1070,952,835,717,599,481,363,246,129,13, + -102,-216,-329,-440,-550,-659,-766,-871,-974,-1075,-1174,-1270,-1364,-1456,-1544, + -1630,-1714,-1794,-1871,-1945,-2016,-2084,-2148,-2209,-2267,-2321,-2372,-2418,-2462, + -2502,-2538,-2570,-2599,-2624,-2645,-2662,-2676,-2686,-2693,-2695,-2694,-2690,-2682, + -2670,-2655,-2636,-2614,-2589,-2560,-2528,-2493,-2455,-2414,-2370,-2323,-2274,-2221, + -2167,-2109,-2050,-1988,-1923,-1857,-1789,-1719,-1647,-1574,-1499,-1422,-1345,-1266, + -1186,-1105,-1023,-941,-858,-774,-690,-606,-522,-438,-354,-270,-187,-104,-21,61,142, + 222,301,379,456,532,606,679,750,820,888,954,1018,1081,1141,1199,1255,1309,1361, + 1410,1457,1502,1544,1584,1621,1655,1687,1717,1743,1768,1789,1808,1824,1838,1849, + 1857,1863,1866,1867,1864,1860,1853,1843,1831,1816,1800,1780,1759,1735,1709,1681, + 1651,1619,1585,1549,1511,1472,1431,1388,1344,1298,1251,1202,1153,1102,1050,997,943, + 889,833,778,721,664,607,549,491,433,375,317,259,201,143,86,29,-27,-83,-138,-193, + -246,-299,-351,-402,-452,-501,-548,-595,-640,-684,-726,-767,-807,-845,-882,-917, + -950,-982,-1012,-1040,-1067,-1091,-1115,-1136,-1155,-1173,-1189,-1203,-1215,-1226, + -1235,-1241,-1246,-1250,-1251,-1251,-1249,-1245,-1239,-1232,-1223,-1213,-1201,-1187, + -1172,-1155,-1137,-1117,-1096,-1074,-1051,-1026,-1000,-973,-944,-915,-885,-854,-822, + -789,-755,-720,-685,-650,-613,-577,-539,-502,-464,-426,-387,-349,-310,-272,-233, + -194,-156,-118,-80,-42,-4,33,69,105,141,176,210,244,277,309,341,372,401,430,458,485, + 512,537,561,584,606,626,646,665,682,698,713,727,740,751,762,771,778,785,791,795, + 798,800,801,800,799,796,792,787,781,774,766,757,747,736,724,711,697,682,667,650, + 633,616,597,578,558,538,517,496,474,452,429,406,382,359,335,311,286,262,237,213, + 188,163,139,114,90,65,41,17,-6,-30,-53,-75,-98,-120,-141,-162,-183,-203,-222,-241, + -260,-277,-295,-311,-327,-342,-357,-371,-384,-396,-408,-419,-429,-439,-448,-456, + -463,-469,-475,-480,-484,-488,-490,-492,-493,-494,-493,-492,-491,-488,-485,-481, + -477,-472,-466,-460,-453,-445,-437,-428,-419,-410,-399,-389,-378,-366,-354,-342, + -329,-316,-303,-290,-276,-262,-248,-233,-218,-204,-189,-174,-159,-144,-129,-114,-99, + -84,-69,-54,-39,-24,-10,4,18,32,46,59,73,85,98,110,122,134,145,156,167,177,186,196, + 205,213,221,229,236,243,249,255,260,265,269,273,277,280,282,284,286,287,288,288, + 288,287,286,285,283,281,278,275,272,268,264,259,254,249,244,238,232,225,219,212, + 205,198,190,182,175,167,158,150,142,133,125,116,107,98,90,81,72,63,54,46,37,28,20, + 11,3,-5,-13,-21,-29,-37,-45,-52,-59,-66,-73,-79,-86,-92,-98,-104,-109,-114,-119, + -124,-128,-132,-136,-140,-143,-146,-149,-152,-154,-156,-158,-159,-160,-161,-162, + -162,-163,-162,-162,-161,-161,-159,-158,-157,-155,-153,-151,-148,-146,-143,-140, + -137,-133,-130,-126,-122,-118,-114,-110,-106,-101,-97,-92,-88,-83,-78,-73,-68,-64, + -59,-54,-49,-44,-39,-34,-29,-24,-19,-14,-9,-5,0,5,9,14,18,22,26,30,34,38,42,45,49, + 52,55,58,61,64,67,69,72,74,76,78,79,81,82,84,85,86,86,87,88,88,88,88,88,88,88,87, + 87,86,85,84,83,82,80,79,77,75,74,72,70,68,66,64,61,59,57,54,52,49,47,44,42,39,36, + 34,31,28,25,23,20,17,15,12,9,7,4,2,-1,-3,-6,-8,-10,-12,-15,-17,-19,-21,-23,-25, + -26,-28,-30,-31,-33,-34,-36,-37,-38,-39,-40,-41,-42,-43,-43,-44,-45,-45,-45,-46, + -46,-46,-46,-46,-46,-46,-45,-45,-45,-44,-44,-43,-42,-42,-41,-40,-39,-38,-37,-36, + -35,-34,-33,-32,-30,-29,-28,-27,-25,-24,-23,-21,-20,-18,-17,-16,-14,-13,-11,-10,-9, + -7,-6,-5,-3,-2,-1,1,2,3,4,5,7,8,9,10,11,12,13,14,14,15,16,17,17,18,19,19,20,20,21, + 21,21,22,22,22,22,22,23,23,23,23,23,22,22,22,22,22,21,21,21,20,20,20,19,19,18,18, + 17,16,16,15,15,14,13,13,12,11,11,10,9,9,8,7,7,6,5,5,4,3,3,2,1,1,0,-1,-1,-2,-2,-3, + -3,-4,-4,-5,-5,-6,-6,-7,-7,-7,-8,-8,-8,-9,-9,-9,-9,-10,-10,-10,-10,-10,-10,-10, + -10,-11,-11,-11,-11,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-9,-9,-9,-8,-8,-8,-8,-7, + -7,-7,-7,-6,-6,-6,-5,-5,-5,-4,-4,-4,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,0,0,0,0,1,1,1,2, + 2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4, + 4,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2, + -2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { + 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, + 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, + 131072,131072,131072,131072,131072,131072,131072,131071,131071,131071,131071,131071, + 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, + 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, + 131071,131071,131071,131071,131071,131070,131070,131070,131070,131070,131070,131070, + 131070,131070,131070,131070,131069,131069,131069,131069,131069,131069,131068,131068, + 131068,131068,131068,131067,131067,131067,131066,131066,131066,131065,131065,131064, + 131064,131064,131063,131062,131062,131061,131061,131060,131059,131058,131058,131057, + 131056,131055,131054,131053,131052,131051,131049,131048,131047,131045,131044,131042, + 131040,131039,131037,131035,131033,131031,131028,131026,131024,131021,131018,131015, + 131012,131009,131006,131003,130999,130995,130991,130987,130983,130978,130974,130969, + 130964,130959,130953,130947,130941,130935,130929,130922,130915,130908,130900,130892, + 130884,130876,130867,130858,130848,130838,130828,130817,130806,130795,130783,130771, + 130758,130745,130731,130717,130702,130687,130671,130655,130638,130621,130603,130585, + 130566,130546,130526,130505,130483,130461,130437,130414,130389,130364,130338,130311, + 130283,130255,130225,130195,130164,130132,130099,130065,130031,129995,129958,129920, + 129881,129841,129800,129758,129715,129671,129625,129578,129531,129481,129431,129379, + 129326,129272,129216,129159,129101,129041,128980,128918,128853,128788,128721,128652, + 128582,128510,128437,128362,128285,128206,128126,128045,127961,127876,127789,127700, + 127609,127517,127422,127326,127228,127128,127026,126922,126816,126708,126598,126486, + 126371,126255,126137,126016,125894,125769,125642,125513,125382,125248,125112,124974, + 124834,124691,124546,124399,124250,124098,123944,123787,123628,123467,123303,123137, + 122969,122798,122625,122449,122271,122090,121907,121722,121534,121343,121150,120955, + 120757,120557,120354,120149,119941,119731,119519,119304,119086,118866,118644,118419, + 118192,117962,117730,117495,117258,117019,116777,116533,116287,116038,115787,115533, + 115277,115019,114759,114496,114232,113965,113695,113424,113150,112874,112597,112317, + 112035,111750,111464,111176,110886,110594,110300,110004,109706,109406,109105,108801, + 108496,108189,107881,107571,107259,106945,106630,106313,105995,105675,105354,105032, + 104708,104382,104056,103728,103398,103068,102736,102403,102070,101735,101398,101061, + 100723,100384,100044,99704,99362,99020,98676,98333,97988,97643,97297,96950,96603, + 96256,95908,95559,95211,94861,94512,94162,93812,93461,93111,92760,92409,92058,91707, + 91356,91005,90654,90303,89952,89601,89250,88899,88549,88199,87849,87499,87150,86801, + 86452,86104,85756,85408,85061,84715,84369,84023,83678,83334,82990,82646,82304,81962, + 81620,81279,80939,80600,80261,79923,79586,79249,78914,78579,78244,77911,77578,77247, + 76916,76585,76256,75927,75600,75273,74947,74622,74297,73974,73651,73329,73008,72688, + 72369,72051,71733,71417,71101,70786,70472,70159,69847,69535,69225,68915,68606,68298, + 67990,67684,67378,67073,66769,66466,66163,65861,65560,65260,64960,64661,64363,64066, + 63769,63473,63178,62884,62590,62296,62004,61712,61421,61130,60840,60550,60262,59973, + 59686,59399,59112,58826,58541,58256,57972,57688,57405,57122,56840,56558,56277,55996, + 55715,55436,55156,54877,54599,54321,54043,53766,53490,53213,52938,52662,52387,52113, + 51839,51565,51292,51019,50747,50475,50203,49932,49661,49391,49121,48852,48583,48314, + 48046,47778,47511,47244,46978,46712,46446,46181,45917,45653,45389,45126,44864,44601, + 44340,44079,43818,43558,43299,43040,42782,42524,42267,42010,41754,41499,41244,40990, + 40737,40484,40232,39980,39729,39479,39230,38981,38733,38486,38239,37994,37749,37504, + 37261,37018,36777,36536,36296,36056,35818,35580,35343,35108,34873,34639,34405,34173, + 33942,33712,33482,33254,33026,32800,32574,32349,32126,31903,31682,31461,31242,31023, + 30806,30589,30374,30160,29946,29734,29523,29313,29104,28896,28689,28483,28278,28074, + 27872,27670,27470,27270,27072,26875,26678,26483,26289,26096,25904,25713,25524,25335, + 25147,24961,24775,24591,24407,24225,24043,23863,23684,23505,23328,23152,22976,22802, + 22628,22456,22285,22114,21945,21776,21608,21442,21276,21111,20947,20784,20622,20460, + 20300,20140,19981,19823,19666,19510,19355,19200,19046,18893,18741,18589,18438,18288, + 18139,17990,17843,17696,17549,17403,17258,17114,16970,16827,16685,16543,16402,16262, + 16122,15983,15845,15707,15569,15433,15296,15161,15026,14891,14758,14624,14492,14359, + 14228,14097,13966,13836,13707,13578,13449,13321,13194,13067,12941,12815,12689,12565, + 12440,12317,12193,12071,11948,11826,11705,11584,11464,11344,11225,11107,10988,10871, + 10753,10637,10521,10405,10290,10175,10061,9948,9835,9722,9610,9499,9388,9278,9168, + 9059,8950,8842,8735,8628,8522,8416,8311,8206,8102,7998,7896,7793,7692,7591,7490, + 7390,7291,7192,7094,6997,6900,6804,6709,6614,6520,6426,6333,6241,6149,6058,5968, + 5878,5789,5700,5613,5526,5439,5353,5268,5184,5100,5017,4935,4853,4772,4691,4611, + 4532,4454,4376,4299,4222,4146,4071,3997,3923,3849,3777,3705,3634,3563,3493,3423, + 3354,3286,3219,3152,3085,3020,2954,2890,2826,2762,2700,2637,2576,2515,2454,2394, + 2335,2276,2218,2160,2102,2046,1989,1934,1878,1824,1769,1716,1662,1610,1557,1505, + 1454,1403,1352,1302,1253,1203,1155,1106,1058,1011,963,917,870,824,778,733,688,643, + 599,555,512,468,425,383,341,299,257,216,175,134,93,53,13,-26,-65,-105,-143,-182, + -220,-258,-296,-333,-370,-407,-444,-480,-516,-552,-588,-623,-659,-694,-728,-763, + -797,-831,-865,-898,-932,-965,-997,-1030,-1062,-1094,-1126,-1158,-1189,-1220,-1251, + -1282,-1312,-1343,-1373,-1402,-1432,-1461,-1490,-1519,-1547,-1575,-1603,-1631,-1659, + -1686,-1713,-1739,-1766,-1792,-1818,-1844,-1869,-1894,-1919,-1944,-1968,-1992,-2016, + -2039,-2063,-2086,-2108,-2131,-2153,-2175,-2196,-2218,-2239,-2259,-2280,-2300,-2320, + -2339,-2359,-2378,-2396,-2415,-2433,-2451,-2469,-2486,-2503,-2520,-2536,-2552,-2568, + -2584,-2599,-2614,-2629,-2644,-2658,-2672,-2686,-2699,-2712,-2725,-2738,-2750,-2762, + -2774,-2786,-2797,-2808,-2819,-2829,-2840,-2850,-2860,-2869,-2878,-2888,-2896,-2905, + -2914,-2922,-2930,-2938,-2945,-2953,-2960,-2967,-2973,-2980,-2986,-2992,-2998,-3004, + -3010,-3015,-3020,-3026,-3030,-3035,-3040,-3044,-3048,-3053,-3057,-3060,-3064,-3068, + -3071,-3074,-3077,-3080,-3083,-3086,-3089,-3091,-3094,-3096,-3098,-3100,-3102,-3104, + -3106,-3108,-3109,-3111,-3112,-3113,-3115,-3116,-3117,-3118,-3119,-3120,-3120,-3121, + -3122,-3122,-3123,-3123,-3123,-3124,-3124,-3124,-3124,-3124,-3124,-3124,-3124,-3123, + -3123,-3123,-3122,-3122,-3121,-3121,-3120,-3120,-3119,-3118,-3117,-3116,-3115,-3114, + -3113,-3112,-3111,-3110,-3108,-3107,-3105,-3104,-3102,-3101,-3099,-3097,-3096,-3094, + -3092,-3090,-3088,-3086,-3083,-3081,-3079,-3076,-3074,-3071,-3069,-3066,-3063,-3061, + -3058,-3055,-3052,-3049,-3045,-3042,-3039,-3035,-3032,-3028,-3025,-3021,-3017,-3013, + -3010,-3005,-3001,-2997,-2993,-2989,-2984,-2980,-2975,-2971,-2966,-2961,-2956,-2951, + -2946,-2941,-2936,-2931,-2925,-2920,-2915,-2909,-2903,-2898,-2892,-2886,-2880,-2874, + -2868,-2862,-2856,-2850,-2843,-2837,-2830,-2824,-2817,-2811,-2804,-2797,-2791,-2784, + -2777,-2770,-2763,-2756,-2749,-2742,-2734,-2727,-2720,-2713,-2705,-2698,-2690,-2683, + -2675,-2668,-2660,-2653,-2645,-2637,-2630,-2622,-2614,-2606,-2599,-2591,-2583,-2575, + -2567,-2559,-2551,-2544,-2536,-2528,-2520,-2512,-2504,-2496,-2488,-2480,-2472,-2464, + -2456,-2448,-2440,-2432,-2424,-2416,-2408,-2400,-2392,-2384,-2376,-2368,-2360,-2352, + -2344,-2336,-2328,-2321,-2313,-2305,-2297,-2289,-2281,-2273,-2266,-2258,-2250,-2242, + -2234,-2227,-2219,-2211,-2203,-2196,-2188,-2180,-2172,-2165,-2157,-2149,-2142,-2134, + -2127,-2119,-2111,-2104,-2096,-2089,-2081,-2074,-2066,-2059,-2051,-2044,-2036,-2029, + -2021,-2014,-2006,-1999,-1991,-1984,-1976,-1969,-1962,-1954,-1947,-1939,-1932,-1925, + -1917,-1910,-1902,-1895,-1888,-1880,-1873,-1865,-1858,-1851,-1843,-1836,-1829,-1821, + -1814,-1806,-1799,-1792,-1784,-1777,-1770,-1762,-1755,-1747,-1740,-1733,-1725,-1718, + -1711,-1703,-1696,-1689,-1681,-1674,-1667,-1659,-1652,-1644,-1637,-1630,-1622,-1615, + -1608,-1600,-1593,-1586,-1578,-1571,-1564,-1556,-1549,-1542,-1535,-1527,-1520,-1513, + -1506,-1498,-1491,-1484,-1477,-1469,-1462,-1455,-1448,-1441,-1433,-1426,-1419,-1412, + -1405,-1398,-1391,-1384,-1377,-1370,-1363,-1356,-1349,-1342,-1335,-1328,-1321,-1314, + -1307,-1300,-1293,-1287,-1280,-1273,-1266,-1260,-1253,-1246,-1240,-1233,-1226,-1220, + -1213,-1207,-1200,-1193,-1187,-1181,-1174,-1168,-1161,-1155,-1149,-1142,-1136,-1130, + -1123,-1117,-1111,-1105,-1099,-1093,-1087,-1081,-1074,-1068,-1062,-1057,-1051,-1045, + -1039,-1033,-1027,-1021,-1015,-1010,-1004,-998,-992,-987,-981,-976,-970,-964,-959, + -953,-948,-942,-937,-931,-926,-920,-915,-910,-904,-899,-894,-888,-883,-878,-873, + -868,-862,-857,-852,-847,-842,-837,-832,-827,-822,-817,-812,-807,-802,-797,-792, + -787,-782,-777,-772,-768,-763,-758,-753,-748,-744,-739,-734,-729,-725,-720,-715, + -711,-706,-702,-697,-692,-688,-683,-679,-674,-670,-665,-661,-657,-652,-648,-643, + -639,-635,-630,-626,-622,-617,-613,-609,-605,-600,-596,-592,-588,-584,-579,-575, + -571,-567,-563,-559,-555,-551,-547,-543,-539,-535,-531,-527,-523,-519,-516,-512, + -508,-504,-500,-497,-493,-489,-485,-482,-478,-474,-471,-467,-463,-460,-456,-453, + -449,-446,-442,-439,-435,-432,-428,-425,-422,-418,-415,-412,-408,-405,-402,-399, + -395,-392,-389,-386,-383,-379,-376,-373,-370,-367,-364,-361,-358,-355,-352,-349, + -346,-343,-340,-338,-335,-332,-329,-326,-323,-321,-318,-315,-312,-310,-307,-304, + -302,-299,-296,-294,-291,-289,-286,-283,-281,-278,-276,-273,-271,-268,-266,-264, + -261,-259,-256,-254,-252,-249,-247,-245,-242,-240,-238,-236,-233,-231,-229,-227, + -224,-222,-220,-218,-216,-214,-212,-209,-207,-205,-203,-201,-199,-197,-195,-193, + -191,-189,-187,-185,-183,-181,-180,-178,-176,-174,-172,-170,-168,-166,-165,-163, + -161,-159,-157,-156,-154,-152,-151,-149,-147,-145,-144,-142,-140,-139,-137,-136, + -134,-132,-131,-129,-128,-126,-124,-123,-121,-120,-118,-117,-115,-114,-113,-111, + -110,-108,-107,-105,-104,-103,-101,-100,-99,-97,-96,-95,-93,-92,-91,-89,-88,-87,-86, + -84,-83,-82,-81,-80,-78,-77,-76,-75,-74,-73,-71,-70,-69,-68,-67,-66,-65,-64,-63, + -62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-46,-45,-44, + -43,-42,-41,-40,-40,-39,-38,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-30,-29,-28, + -27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-21,-20,-19,-19,-18,-18,-17,-16,-16,-15, + -15,-14,-14,-13,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-5,-4,-4,-3, + -3,-2,-2,-1,-1,-1,0,0,0,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,9, + 10,10,10,10,11,11,11,11,11,12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,15, + 15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16, + 16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14, + 14,14,14,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,10, + 10,10,10,10,10,10,9,9,9,9,9,9,8,8,8,8,8,8,8,7,7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,5,4, + 4,4,4,4,4,3,3,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0, + }, + { + 131072,131072,131072,131072,131072,131072,131072,131072,131071,131071,131071, + 131071,131071,131070,131070,131070,131069,131069,131068,131068,131067,131066,131066, + 131065,131064,131063,131061,131060,131058,131057,131055,131053,131051,131048,131046, + 131043,131040,131037,131033,131029,131025,131021,131016,131011,131005,130999,130993, + 130986,130978,130970,130962,130953,130943,130933,130922,130910,130897,130884,130870, + 130855,130839,130822,130804,130785,130765,130744,130721,130697,130672,130646,130618, + 130589,130558,130525,130491,130455,130417,130377,130336,130292,130246,130198,130147, + 130095,130039,129982,129921,129858,129792,129723,129651,129576,129497,129416,129330, + 129242,129149,129053,128953,128849,128741,128628,128512,128390,128265,128134,127998, + 127858,127712,127561,127405,127243,127076,126903,126723,126538,126346,126148,125944, + 125733,125515,125290,125058,124818,124572,124317,124055,123785,123508,123222,122927, + 122624,122313,121993,121664,121326,120978,120622,120255,119880,119494,119099,118693, + 118278,117852,117415,116968,116510,116042,115562,115072,114570,114057,113532,112996, + 112448,111889,111317,110734,110139,109532,108912,108280,107636,106980,106311,105630, + 104936,104229,103510,102778,102034,101276,100506,99724,98928,98120,97299,96466,95620, + 94761,93889,93005,92109,91200,90279,89345,88400,87442,86472,85490,84497,83492,82475, + 81447,80408,79358,78297,77225,76142,75050,73947,72834,71712,70580,69439,68289,67130, + 65963,64787,63604,62413,61215,60009,58797,57578,56354,55123,53887,52646,51401,50151, + 48897,47639,46378,45115,43848,42580,41310,40039,38767,37495,36223,34951,33680,32410, + 31142,29877,28614,27354,26098,24846,23598,22355,21118,19887,18662,17444,16233,15030, + 13835,12649,11472,10304,9147,8001,6865,5741,4629,3529,2442,1368,308,-738,-1769,-2786, + -3787,-4772,-5741,-6693,-7628,-8546,-9447,-10329,-11192,-12037,-12863,-13669,-14455, + -15221,-15967,-16692,-17396,-18079,-18741,-19380,-19998,-20593,-21167,-21717,-22245, + -22750,-23232,-23690,-24126,-24538,-24926,-25291,-25632,-25949,-26243,-26513,-26759, + -26981,-27179,-27354,-27505,-27633,-27737,-27818,-27875,-27910,-27921,-27909,-27875, + -27818,-27739,-27638,-27516,-27371,-27206,-27019,-26812,-26584,-26336,-26069,-25782, + -25476,-25151,-24808,-24448,-24070,-23674,-23263,-22835,-22391,-21933,-21459,-20972, + -20470,-19955,-19428,-18888,-18337,-17775,-17202,-16619,-16027,-15425,-14816,-14199, + -13574,-12943,-12306,-11663,-11016,-10364,-9709,-9051,-8390,-7728,-7064,-6400,-5735, + -5071,-4408,-3747,-3088,-2432,-1779,-1131,-486,153,786,1413,2034,2647,3253,3850,4439, + 5018,5587,6147,6696,7233,7759,8274,8776,9265,9741,10204,10652,11087,11507,11912, + 12303,12677,13037,13380,13707,14018,14313,14590,14851,15095,15321,15531,15723,15897, + 16055,16194,16316,16420,16507,16577,16628,16663,16679,16679,16661,16627,16575,16507, + 16422,16320,16203,16069,15920,15755,15575,15380,15170,14946,14708,14456,14191,13913, + 13622,13319,13004,12678,12340,11992,11633,11265,10887,10501,10106,9703,9292,8875, + 8451,8021,7585,7145,6699,6250,5797,5341,4883,4422,3960,3497,3033,2570,2106,1644, + 1183,724,268,-186,-636,-1082,-1524,-1961,-2393,-2820,-3240,-3654,-4061,-4460,-4852, + -5236,-5611,-5977,-6334,-6682,-7019,-7347,-7664,-7970,-8265,-8549,-8822,-9082,-9331, + -9567,-9791,-10002,-10200,-10386,-10558,-10718,-10864,-10997,-11116,-11222,-11314, + -11393,-11458,-11510,-11548,-11573,-11584,-11582,-11566,-11537,-11496,-11441,-11373, + -11293,-11200,-11095,-10978,-10849,-10708,-10556,-10392,-10218,-10032,-9837,-9631, + -9415,-9190,-8955,-8712,-8460,-8200,-7931,-7656,-7373,-7083,-6787,-6485,-6177,-5864, + -5547,-5224,-4898,-4568,-4235,-3899,-3560,-3220,-2878,-2535,-2191,-1847,-1502,-1158, + -816,-474,-134,204,540,872,1202,1528,1849,2167,2480,2788,3091,3388,3678,3963,4241, + 4512,4776,5033,5281,5522,5754,5979,6194,6400,6598,6786,6965,7134,7293,7443,7582, + 7711,7830,7939,8038,8126,8203,8271,8327,8373,8409,8434,8448,8452,8446,8429,8403, + 8366,8319,8262,8195,8119,8033,7938,7834,7721,7599,7469,7330,7183,7028,6865,6695, + 6518,6334,6143,5946,5743,5534,5319,5100,4875,4646,4412,4175,3934,3689,3442,3192, + 2940,2685,2429,2172,1913,1654,1394,1135,875,616,359,102,-153,-406,-657,-906,-1152, + -1394,-1634,-1870,-2101,-2329,-2552,-2771,-2985,-3193,-3396,-3594,-3785,-3971,-4150, + -4323,-4490,-4649,-4802,-4947,-5086,-5217,-5340,-5456,-5564,-5665,-5757,-5842,-5919, + -5987,-6048,-6101,-6145,-6181,-6209,-6229,-6241,-6245,-6241,-6229,-6210,-6182,-6147, + -6104,-6053,-5996,-5930,-5858,-5779,-5693,-5600,-5501,-5395,-5283,-5165,-5041,-4911, + -4777,-4637,-4491,-4341,-4187,-4028,-3865,-3699,-3528,-3354,-3177,-2998,-2815,-2630, + -2444,-2255,-2064,-1872,-1680,-1486,-1292,-1097,-902,-708,-513,-320,-127,64,254,442, + 629,813,995,1174,1351,1525,1695,1862,2026,2185,2341,2493,2640,2783,2921,3054,3183, + 3306,3424,3537,3645,3746,3843,3933,4018,4097,4170,4237,4298,4353,4402,4445,4482, + 4512,4536,4555,4567,4573,4573,4566,4554,4537,4513,4483,4448,4407,4361,4309,4252, + 4190,4122,4050,3973,3891,3805,3714,3619,3520,3417,3310,3200,3086,2969,2849,2726, + 2600,2472,2341,2209,2074,1938,1800,1660,1520,1378,1236,1093,950,806,663,520,377,235, + 93,-48,-187,-325,-462,-597,-730,-862,-991,-1118,-1242,-1364,-1483,-1599,-1712, + -1822,-1929,-2032,-2132,-2228,-2320,-2409,-2494,-2575,-2651,-2724,-2792,-2856,-2916, + -2971,-3022,-3069,-3111,-3148,-3181,-3210,-3234,-3253,-3268,-3278,-3284,-3285,-3282, + -3275,-3263,-3247,-3227,-3202,-3174,-3141,-3104,-3064,-3019,-2971,-2919,-2864,-2805, + -2743,-2678,-2610,-2539,-2464,-2387,-2308,-2226,-2142,-2055,-1966,-1876,-1783,-1689, + -1594,-1497,-1399,-1299,-1199,-1098,-996,-894,-791,-689,-586,-483,-380,-278,-176,-75, + 26,126,224,322,418,513,606,698,788,877,963,1047,1129,1209,1287,1362,1434,1504, + 1572,1637,1698,1757,1814,1867,1917,1964,2008,2049,2086,2121,2152,2180,2205,2227, + 2245,2260,2272,2280,2286,2288,2287,2283,2276,2265,2252,2236,2216,2194,2169,2142, + 2111,2078,2042,2004,1963,1921,1875,1828,1778,1727,1673,1618,1561,1502,1442,1380, + 1317,1253,1187,1120,1053,984,915,846,775,705,633,562,491,419,348,277,206,135,65,-5, + -74,-142,-209,-276,-341,-406,-469,-531,-592,-651,-709,-765,-820,-873,-924,-974, + -1021,-1067,-1111,-1153,-1193,-1231,-1267,-1301,-1332,-1362,-1389,-1414,-1437,-1457, + -1476,-1492,-1505,-1517,-1526,-1534,-1538,-1541,-1542,-1540,-1536,-1530,-1522,-1512, + -1500,-1486,-1470,-1452,-1432,-1410,-1387,-1362,-1335,-1306,-1276,-1245,-1212,-1178, + -1142,-1105,-1067,-1028,-987,-946,-904,-861,-817,-772,-727,-681,-635,-588,-541,-494, + -446,-399,-351,-303,-255,-208,-160,-113,-66,-20,26,72,117,161,205,248,290,331,371, + 411,449,486,523,558,592,624,656,686,715,743,769,794,817,839,860,879,897,913,928, + 941,953,963,972,979,985,989,992,993,993,992,989,984,979,972,963,954,943,931,917, + 903,887,870,852,833,813,792,771,748,724,700,675,649,623,596,568,540,512,483,453, + 424,394,363,333,302,272,241,210,180,149,119,88,58,28,-1,-30,-59,-88,-115,-143,-170, + -196,-222,-247,-272,-296,-319,-341,-363,-384,-404,-423,-441,-459,-476,-491,-506, + -520,-533,-545,-557,-567,-576,-584,-592,-598,-604,-608,-612,-614,-616,-617,-616, + -615,-613,-610,-607,-602,-597,-591,-583,-576,-567,-558,-548,-537,-526,-514,-501, + -488,-474,-460,-445,-430,-414,-398,-382,-365,-347,-330,-312,-294,-276,-257,-239, + -220,-201,-182,-163,-144,-126,-107,-88,-69,-51,-32,-14,4,22,39,56,73,90,106,122,137, + 152,167,181,195,208,221,233,245,257,267,277,287,296,305,313,320,327,333,339,344, + 348,352,355,358,360,362,363,363,363,362,361,359,357,354,351,347,343,338,333,327, + 321,315,308,301,293,285,277,268,259,250,241,231,221,211,201,190,180,169,158,147, + 136,125,114,103,91,80,69,58,47,36,25,15,4,-7,-17,-27,-37,-47,-56,-66,-75,-84,-92, + -101,-109,-117,-124,-131,-138,-145,-151,-157,-163,-168,-173,-178,-182,-186,-189, + -193,-196,-198,-200,-202,-204,-205,-206,-206,-206,-206,-206,-205,-204,-203,-201, + -199,-197,-194,-191,-188,-185,-181,-178,-174,-169,-165,-160,-155,-150,-145,-140, + -135,-129,-123,-117,-111,-105,-99,-93,-87,-81,-74,-68,-62,-55,-49,-43,-36,-30,-24, + -18,-12,-6,0,6,12,18,23,29,34,39,44,49,54,58,63,67,71,75,79,82,86,89,92,95,97,100, + 102,104,106,107,109,110,111,112,112,113,113,113,113,113,112,112,111,110,109,107, + 106,104,103,101,99,97,94,92,89,87,84,81,78,75,72,69,66,63,60,56,53,50,46,43,39,36, + 32,29,25,22,18,15,12,8,5,2,-1,-5,-8,-11,-14,-17,-19,-22,-25,-27,-30,-32,-35,-37, + -39,-41,-43,-45,-46,-48,-50,-51,-52,-53,-54,-55,-56,-57,-58,-58,-59,-59,-59,-59, + -59,-59,-59,-59,-58,-58,-57,-57,-56,-55,-54,-54,-53,-51,-50,-49,-48,-46,-45,-44, + -42,-41,-39,-37,-36,-34,-32,-31,-29,-27,-25,-23,-22,-20,-18,-16,-14,-12,-11,-9,-7, + -5,-4,-2,0,1,3,5,6,8,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,25,26,27,27,28, + 28,29,29,29,29,29,30,30,30,30,29,29,29,29,29,28,28,27,27,27,26,25,25,24,24,23,22, + 21,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,7,6,5,4,3,2,1,0,0,-1,-2,-3,-3,-4, + -5,-6,-6,-7,-7,-8,-9,-9,-10,-10,-11,-11,-11,-12,-12,-12,-13,-13,-13,-13,-14,-14, + -14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-13,-13,-13,-13,-13,-12,-12,-12,-11, + -11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-7,-7,-6,-6,-6,-5,-5,-4,-4,-3,-3,-3,-2,-2,-1,-1, + -1,0,0,1,1,1,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,5,5,5,5,5,5,5,4,4,4,4,4,4,3,3,3,3,3,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,-1, + -1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-3,-3,-3,-3,-3,-3, + -3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + }, +}; diff --git a/src/uaelib.cpp b/src/uaelib.cpp index 2beea53c..1f3bb20b 100755 --- a/src/uaelib.cpp +++ b/src/uaelib.cpp @@ -1,432 +1,432 @@ -/* - * UAE - The U*nix Amiga Emulator - * - * UAE Library v0.1 - * - * (c) 1996 Tauno Taipaleenmaki - * - * Change UAE parameters and other stuff from inside the emulation. - */ - -#include "sysconfig.h" -#include "sysdeps.h" - -#include -#include - -#include "options.h" -#include "uae.h" -#include "memory.h" -#include "custom.h" -#include "newcpu.h" -#include "xwin.h" -#include "autoconf.h" -#include "traps.h" -#include "disk.h" -#include "debug.h" -#include "gensound.h" -#include "picasso96.h" -#include "filesys.h" - -/* - * Returns UAE Version - */ -static uae_u32 emulib_GetVersion (void) -{ - return version; -} - -/* - * Resets your amiga - */ -static uae_u32 emulib_HardReset (void) -{ - uae_reset(1, 1); - return 0; -} - -static uae_u32 emulib_Reset (void) -{ - uae_reset(0, 0); - return 0; -} - -/* - * Enables SOUND - */ -static uae_u32 emulib_EnableSound (uae_u32 val) -{ - if (!sound_available || currprefs.produce_sound == 2) - return 0; - - currprefs.produce_sound = val; - return 1; -} - -/* - * Enables FAKE JOYSTICK - */ -static uae_u32 emulib_EnableJoystick (uae_u32 val) -{ - currprefs.jports[0].id = val & 255; - currprefs.jports[1].id = (val >> 8) & 255; - return 1; -} - -/* - * Sets the framerate - */ -static uae_u32 emulib_SetFrameRate (uae_u32 val) -{ - if (val == 0) - return 0; - else if (val > 20) - return 0; - else { - currprefs.gfx_framerate = val; - return 1; - } -} - -/* - * Changes keyboard language settings - */ -static uae_u32 emulib_ChangeLanguage (uae_u32 which) -{ - if(which > 0) - return 0; - return 1; -} - -/* The following ones don't work as we never realloc the arrays... */ -/* - * Changes chip memory size - * (reboots) - */ -static uae_u32 REGPARAM2 emulib_ChgCMemSize (uae_u32 memsize) -{ - if (memsize != 0x80000 && memsize != 0x100000 && - memsize != 0x200000) { - memsize = 0x200000; - write_log (_T("Unsupported chipmem size!\n")); - } - m68k_dreg (regs, 0) = 0; - - changed_prefs.chipmem_size = memsize; - uae_reset(1, 1); - return 1; -} - -/* - * Changes slow memory size - * (reboots) - */ -static uae_u32 REGPARAM2 emulib_ChgSMemSize (uae_u32 memsize) -{ - if (memsize != 0x80000 && memsize != 0x100000 && - memsize != 0x180000 && memsize != 0x1C0000) { - memsize = 0; - write_log (_T("Unsupported bogomem size!\n")); - } - - m68k_dreg (regs, 0) = 0; - changed_prefs.bogomem_size = memsize; - uae_reset (1, 1); - return 1; -} - -/* - * Changes fast memory size - * (reboots) - */ -static uae_u32 REGPARAM2 emulib_ChgFMemSize (uae_u32 memsize) -{ - if (memsize != 0x100000 && memsize != 0x200000 && - memsize != 0x400000 && memsize != 0x800000) { - memsize = 0; - write_log (_T("Unsupported fastmem size!\n")); - } - m68k_dreg (regs, 0) = 0; - changed_prefs.fastmem_size = memsize; - uae_reset (1, 1); - return 0; -} - -/* - * Inserts a disk - */ -static uae_u32 emulib_InsertDisk (uaecptr name, uae_u32 drive) -{ - int i = 0; - char real_name[256]; - TCHAR *s; - - if (drive > 3) - return 0; - - while ((real_name[i] = get_byte (name + i)) != 0 && i++ != 254) - ; - - if (i == 255) - return 0; /* ENAMETOOLONG */ - - s = au (real_name); - _tcscpy (changed_prefs.floppyslots[drive].df, s); - xfree (s); - - return 1; -} - -/* - * Exits the emulator - */ -static uae_u32 emulib_ExitEmu (void) -{ - gui_message("Amiga sent signal to quit emulator."); - uae_quit (); - return 1; -} - -/* - * Gets UAE Configuration - */ -static uae_u32 emulib_GetUaeConfig (uaecptr place) -{ - int i, j; - - put_long (place, version); - put_long (place + 4, chipmem_bank.allocated); - put_long (place + 8, bogomem_bank.allocated); - put_long (place + 12, fastmem_bank.allocated); - put_long (place + 16, currprefs.gfx_framerate); - put_long (place + 20, currprefs.produce_sound); - put_long (place + 24, currprefs.jports[0].id | (currprefs.jports[1].id << 8)); - put_long (place + 28, 0); - if (disk_empty (0)) - put_byte (place + 32, 0); - else - put_byte (place + 32, 1); - if (disk_empty (1)) - put_byte (place + 33, 0); - else - put_byte (place + 33, 1); - if (disk_empty(2)) - put_byte (place + 34, 0); - else - put_byte (place + 34, 1); - if (disk_empty(3)) - put_byte (place + 35, 0); - else - put_byte (place + 35, 1); - - for (j = 0; j < 4; j++) { - char *s = ua (currprefs.floppyslots[j].df); - for (i = 0; i < 256; i++) - put_byte (place + 36 + i + j * 256, s[i]); - xfree (s); - } - return 1; -} - -/* - * Sets UAE Configuration - * - * NOT IMPLEMENTED YET - */ -static uae_u32 emulib_SetUaeConfig (uaecptr place) -{ - return 1; -} - -/* - * Gets the name of the disk in the given drive - */ -static uae_u32 emulib_GetDisk (uae_u32 drive, uaecptr name) -{ - int i; - if (drive > 3) - return 0; - - for (i = 0;i < 256; i++) { - put_byte (name + i, currprefs.floppyslots[drive].df[i]); - } - return 1; -} - -/* - * Enter debugging state - */ -static uae_u32 emulib_Debug (void) -{ -#ifdef DEBUGGER - activate_debugger (); - return 1; -#else - return 0; -#endif -} - - -#define CREATE_NATIVE_FUNC_PTR uae_u32 (* native_func)( uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, \ - uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32) -#define SET_NATIVE_FUNC(x) native_func = (uae_u32 (*)(uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32))(x) -#define CALL_NATIVE_FUNC( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) if(native_func) native_func( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) -/* A0 - Contains a ptr to the native .obj data. This ptr is Amiga-based. */ -/* We simply find the first function in this .obj data, and execute it. */ -static uae_u32 REGPARAM2 emulib_ExecuteNativeCode (void) -{ -#if 0 - uaecptr object_AAM = m68k_areg (regs, 0); - uae_u32 d1 = m68k_dreg (regs, 1); - uae_u32 d2 = m68k_dreg (regs, 2); - uae_u32 d3 = m68k_dreg (regs, 3); - uae_u32 d4 = m68k_dreg (regs, 4); - uae_u32 d5 = m68k_dreg (regs, 5); - uae_u32 d6 = m68k_dreg (regs, 6); - uae_u32 d7 = m68k_dreg (regs, 7); - uae_u32 a1 = m68k_areg (regs, 1); - uae_u32 a2 = m68k_areg (regs, 2); - uae_u32 a3 = m68k_areg (regs, 3); - uae_u32 a4 = m68k_areg (regs, 4); - uae_u32 a5 = m68k_areg (regs, 5); - uae_u32 a6 = m68k_areg (regs, 6); - - uae_u8* object_UAM = NULL; - CREATE_NATIVE_FUNC_PTR; - - if( get_mem_bank( object_AAM ).check( object_AAM, 1 ) ) - object_UAM = get_mem_bank( object_AAM).xlateaddr( object_AAM ); - - if(object_UAM) { - SET_NATIVE_FUNC( FindFunctionInObject( object_UAM ) ); - CALL_NATIVE_FUNC( d1, d2, d3, d4, d5, d6, d7, a1, a2, a3, a4, a5, a6); - } - return 1; -#endif - return 0; -} - -static uae_u32 emulib_Minimize (void) -{ - return 0; // OSDEP_minimize_uae(); -} - -static int native_dos_op (uae_u32 mode, uae_u32 p1, uae_u32 p2, uae_u32 p3) -{ - TCHAR tmp[MAX_DPATH]; - char *s; - int v, i; - - if (mode) - return -1; - /* receive native path from lock - * p1 = dos.library:Lock, p2 = buffer, p3 = max buffer size - */ - v = get_native_path (p1, tmp); - if (v) - return v; - s = ua (tmp); - for (i = 0; i <= strlen (s) && i < p3 - 1; i++) { - put_byte (p2 + i, s[i]); - put_byte (p2 + i + 1, 0); - } - xfree (s); - return 0; -} - -extern uae_u32 picasso_demux (uae_u32 arg, TrapContext *context); - -static uae_u32 REGPARAM2 uaelib_demux2 (TrapContext *context) -{ -#define ARG0 (get_long (m68k_areg (regs, 7) + 4)) -#define ARG1 (get_long (m68k_areg (regs, 7) + 8)) -#define ARG2 (get_long (m68k_areg (regs, 7) + 12)) -#define ARG3 (get_long (m68k_areg (regs, 7) + 16)) -#define ARG4 (get_long (m68k_areg (regs, 7) + 20)) -#define ARG5 (get_long (m68k_areg (regs, 7) + 24)) - -#ifdef PICASSO96 - if (ARG0 >= 16 && ARG0 <= 39) - return picasso_demux (ARG0, context); -#endif - - switch (ARG0) - { - case 0: return emulib_GetVersion (); - case 1: return emulib_GetUaeConfig (ARG1); - case 2: return emulib_SetUaeConfig (ARG1); - case 3: return emulib_HardReset (); - case 4: return emulib_Reset (); - case 5: return emulib_InsertDisk (ARG1, ARG2); - case 6: return emulib_EnableSound (ARG1); - case 7: return emulib_EnableJoystick (ARG1); - case 8: return emulib_SetFrameRate (ARG1); - case 9: return emulib_ChgCMemSize (ARG1); - case 10: return emulib_ChgSMemSize (ARG1); - case 11: return emulib_ChgFMemSize (ARG1); - case 12: return emulib_ChangeLanguage (ARG1); - /* The next call brings bad luck */ - case 13: return emulib_ExitEmu (); - case 14: return emulib_GetDisk (ARG1, ARG2); - case 15: return emulib_Debug (); - - case 68: return emulib_Minimize (); - case 69: return emulib_ExecuteNativeCode (); - - case 70: return 0; /* RESERVED. Something uses this.. */ - - case 80: - return 0xffffffff; - case 81: return cfgfile_uaelib (ARG1, ARG2, ARG3, ARG4); - case 82: return cfgfile_uaelib_modify (ARG1, ARG2, ARG3, ARG4, ARG5); - case 83: return 0; -#ifdef DEBUGGER - case 84: return mmu_init (ARG1, ARG2, ARG3); -#endif - case 85: return native_dos_op (ARG1, ARG2, ARG3, ARG4); - case 86: - if (valid_address(ARG1, 1)) { - TCHAR *s = au ((char*)get_real_address (ARG1)); - write_log (_T("DBG: %s\n"), s); - xfree (s); - return 1; - } - return 0; - case 87: - { - uae_u32 d0, d1; - d0 = emulib_target_getcpurate (ARG1, &d1); - m68k_dreg (regs, 1) = d1; - return d0; - } - } - return 0; -} - -static uae_u32 REGPARAM2 uaelib_demux (TrapContext *context) -{ - uae_u32 v; - - v = uaelib_demux2 (context); - return v; -} - -/* - * Installs the UAE LIBRARY - */ -void emulib_install (void) -{ - uaecptr a; - if (!uae_boot_rom) - return; - a = here (); - org (rtarea_base + 0xFF60); -#if 0 - dw (0x4eb9); - dw ((rtarea_base >> 16) | get_word(rtarea_base + 36)); - dw (get_word(rtarea_base + 38) + 12); -#endif - calltrap (deftrapres (uaelib_demux, 0, _T("uaelib_demux"))); - dw (RTS); - org (a); -} +/* + * UAE - The U*nix Amiga Emulator + * + * UAE Library v0.1 + * + * (c) 1996 Tauno Taipaleenmaki + * + * Change UAE parameters and other stuff from inside the emulation. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "xwin.h" +#include "autoconf.h" +#include "traps.h" +#include "disk.h" +#include "debug.h" +#include "gensound.h" +#include "picasso96.h" +#include "filesys.h" + +/* + * Returns UAE Version + */ +static uae_u32 emulib_GetVersion (void) +{ + return version; +} + +/* + * Resets your amiga + */ +static uae_u32 emulib_HardReset (void) +{ + uae_reset(1, 1); + return 0; +} + +static uae_u32 emulib_Reset (void) +{ + uae_reset(0, 0); + return 0; +} + +/* + * Enables SOUND + */ +static uae_u32 emulib_EnableSound (uae_u32 val) +{ + if (!sound_available || currprefs.produce_sound == 2) + return 0; + + currprefs.produce_sound = val; + return 1; +} + +/* + * Enables FAKE JOYSTICK + */ +static uae_u32 emulib_EnableJoystick (uae_u32 val) +{ + currprefs.jports[0].id = val & 255; + currprefs.jports[1].id = (val >> 8) & 255; + return 1; +} + +/* + * Sets the framerate + */ +static uae_u32 emulib_SetFrameRate (uae_u32 val) +{ + if (val == 0) + return 0; + else if (val > 20) + return 0; + else { + currprefs.gfx_framerate = val; + return 1; + } +} + +/* + * Changes keyboard language settings + */ +static uae_u32 emulib_ChangeLanguage (uae_u32 which) +{ + if(which > 0) + return 0; + return 1; +} + +/* The following ones don't work as we never realloc the arrays... */ +/* + * Changes chip memory size + * (reboots) + */ +static uae_u32 REGPARAM2 emulib_ChgCMemSize (uae_u32 memsize) +{ + if (memsize != 0x80000 && memsize != 0x100000 && + memsize != 0x200000) { + memsize = 0x200000; + write_log (_T("Unsupported chipmem size!\n")); + } + m68k_dreg (regs, 0) = 0; + + changed_prefs.chipmem_size = memsize; + uae_reset(1, 1); + return 1; +} + +/* + * Changes slow memory size + * (reboots) + */ +static uae_u32 REGPARAM2 emulib_ChgSMemSize (uae_u32 memsize) +{ + if (memsize != 0x80000 && memsize != 0x100000 && + memsize != 0x180000 && memsize != 0x1C0000) { + memsize = 0; + write_log (_T("Unsupported bogomem size!\n")); + } + + m68k_dreg (regs, 0) = 0; + changed_prefs.bogomem_size = memsize; + uae_reset (1, 1); + return 1; +} + +/* + * Changes fast memory size + * (reboots) + */ +static uae_u32 REGPARAM2 emulib_ChgFMemSize (uae_u32 memsize) +{ + if (memsize != 0x100000 && memsize != 0x200000 && + memsize != 0x400000 && memsize != 0x800000) { + memsize = 0; + write_log (_T("Unsupported fastmem size!\n")); + } + m68k_dreg (regs, 0) = 0; + changed_prefs.fastmem_size = memsize; + uae_reset (1, 1); + return 0; +} + +/* + * Inserts a disk + */ +static uae_u32 emulib_InsertDisk (uaecptr name, uae_u32 drive) +{ + int i = 0; + char real_name[256]; + TCHAR *s; + + if (drive > 3) + return 0; + + while ((real_name[i] = get_byte (name + i)) != 0 && i++ != 254) + ; + + if (i == 255) + return 0; /* ENAMETOOLONG */ + + s = au (real_name); + _tcscpy (changed_prefs.floppyslots[drive].df, s); + xfree (s); + + return 1; +} + +/* + * Exits the emulator + */ +static uae_u32 emulib_ExitEmu (void) +{ + gui_message("Amiga sent signal to quit emulator."); + uae_quit (); + return 1; +} + +/* + * Gets UAE Configuration + */ +static uae_u32 emulib_GetUaeConfig (uaecptr place) +{ + int i, j; + + put_long (place, version); + put_long (place + 4, chipmem_bank.allocated); + put_long (place + 8, bogomem_bank.allocated); + put_long (place + 12, fastmem_bank.allocated); + put_long (place + 16, currprefs.gfx_framerate); + put_long (place + 20, currprefs.produce_sound); + put_long (place + 24, currprefs.jports[0].id | (currprefs.jports[1].id << 8)); + put_long (place + 28, 0); + if (disk_empty (0)) + put_byte (place + 32, 0); + else + put_byte (place + 32, 1); + if (disk_empty (1)) + put_byte (place + 33, 0); + else + put_byte (place + 33, 1); + if (disk_empty(2)) + put_byte (place + 34, 0); + else + put_byte (place + 34, 1); + if (disk_empty(3)) + put_byte (place + 35, 0); + else + put_byte (place + 35, 1); + + for (j = 0; j < 4; j++) { + char *s = ua (currprefs.floppyslots[j].df); + for (i = 0; i < 256; i++) + put_byte (place + 36 + i + j * 256, s[i]); + xfree (s); + } + return 1; +} + +/* + * Sets UAE Configuration + * + * NOT IMPLEMENTED YET + */ +static uae_u32 emulib_SetUaeConfig (uaecptr place) +{ + return 1; +} + +/* + * Gets the name of the disk in the given drive + */ +static uae_u32 emulib_GetDisk (uae_u32 drive, uaecptr name) +{ + int i; + if (drive > 3) + return 0; + + for (i = 0;i < 256; i++) { + put_byte (name + i, currprefs.floppyslots[drive].df[i]); + } + return 1; +} + +/* + * Enter debugging state + */ +static uae_u32 emulib_Debug (void) +{ +#ifdef DEBUGGER + activate_debugger (); + return 1; +#else + return 0; +#endif +} + + +#define CREATE_NATIVE_FUNC_PTR uae_u32 (* native_func)( uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, \ + uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32) +#define SET_NATIVE_FUNC(x) native_func = (uae_u32 (*)(uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32))(x) +#define CALL_NATIVE_FUNC( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) if(native_func) native_func( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) +/* A0 - Contains a ptr to the native .obj data. This ptr is Amiga-based. */ +/* We simply find the first function in this .obj data, and execute it. */ +static uae_u32 REGPARAM2 emulib_ExecuteNativeCode (void) +{ +#if 0 + uaecptr object_AAM = m68k_areg (regs, 0); + uae_u32 d1 = m68k_dreg (regs, 1); + uae_u32 d2 = m68k_dreg (regs, 2); + uae_u32 d3 = m68k_dreg (regs, 3); + uae_u32 d4 = m68k_dreg (regs, 4); + uae_u32 d5 = m68k_dreg (regs, 5); + uae_u32 d6 = m68k_dreg (regs, 6); + uae_u32 d7 = m68k_dreg (regs, 7); + uae_u32 a1 = m68k_areg (regs, 1); + uae_u32 a2 = m68k_areg (regs, 2); + uae_u32 a3 = m68k_areg (regs, 3); + uae_u32 a4 = m68k_areg (regs, 4); + uae_u32 a5 = m68k_areg (regs, 5); + uae_u32 a6 = m68k_areg (regs, 6); + + uae_u8* object_UAM = NULL; + CREATE_NATIVE_FUNC_PTR; + + if( get_mem_bank( object_AAM ).check( object_AAM, 1 ) ) + object_UAM = get_mem_bank( object_AAM).xlateaddr( object_AAM ); + + if(object_UAM) { + SET_NATIVE_FUNC( FindFunctionInObject( object_UAM ) ); + CALL_NATIVE_FUNC( d1, d2, d3, d4, d5, d6, d7, a1, a2, a3, a4, a5, a6); + } + return 1; +#endif + return 0; +} + +static uae_u32 emulib_Minimize (void) +{ + return 0; // OSDEP_minimize_uae(); +} + +static int native_dos_op (uae_u32 mode, uae_u32 p1, uae_u32 p2, uae_u32 p3) +{ + TCHAR tmp[MAX_DPATH]; + char *s; + int v, i; + + if (mode) + return -1; + /* receive native path from lock + * p1 = dos.library:Lock, p2 = buffer, p3 = max buffer size + */ + v = get_native_path (p1, tmp); + if (v) + return v; + s = ua (tmp); + for (i = 0; i <= strlen (s) && i < p3 - 1; i++) { + put_byte (p2 + i, s[i]); + put_byte (p2 + i + 1, 0); + } + xfree (s); + return 0; +} + +extern uae_u32 picasso_demux (uae_u32 arg, TrapContext *context); + +static uae_u32 REGPARAM2 uaelib_demux2 (TrapContext *context) +{ +#define ARG0 (get_long (m68k_areg (regs, 7) + 4)) +#define ARG1 (get_long (m68k_areg (regs, 7) + 8)) +#define ARG2 (get_long (m68k_areg (regs, 7) + 12)) +#define ARG3 (get_long (m68k_areg (regs, 7) + 16)) +#define ARG4 (get_long (m68k_areg (regs, 7) + 20)) +#define ARG5 (get_long (m68k_areg (regs, 7) + 24)) + +#ifdef PICASSO96 + if (ARG0 >= 16 && ARG0 <= 39) + return picasso_demux (ARG0, context); +#endif + + switch (ARG0) + { + case 0: return emulib_GetVersion (); + case 1: return emulib_GetUaeConfig (ARG1); + case 2: return emulib_SetUaeConfig (ARG1); + case 3: return emulib_HardReset (); + case 4: return emulib_Reset (); + case 5: return emulib_InsertDisk (ARG1, ARG2); + case 6: return emulib_EnableSound (ARG1); + case 7: return emulib_EnableJoystick (ARG1); + case 8: return emulib_SetFrameRate (ARG1); + case 9: return emulib_ChgCMemSize (ARG1); + case 10: return emulib_ChgSMemSize (ARG1); + case 11: return emulib_ChgFMemSize (ARG1); + case 12: return emulib_ChangeLanguage (ARG1); + /* The next call brings bad luck */ + case 13: return emulib_ExitEmu (); + case 14: return emulib_GetDisk (ARG1, ARG2); + case 15: return emulib_Debug (); + + case 68: return emulib_Minimize (); + case 69: return emulib_ExecuteNativeCode (); + + case 70: return 0; /* RESERVED. Something uses this.. */ + + case 80: + return 0xffffffff; + case 81: return cfgfile_uaelib (ARG1, ARG2, ARG3, ARG4); + case 82: return cfgfile_uaelib_modify (ARG1, ARG2, ARG3, ARG4, ARG5); + case 83: return 0; +#ifdef DEBUGGER + case 84: return mmu_init (ARG1, ARG2, ARG3); +#endif + case 85: return native_dos_op (ARG1, ARG2, ARG3, ARG4); + case 86: + if (valid_address(ARG1, 1)) { + TCHAR *s = au ((char*)get_real_address (ARG1)); + write_log (_T("DBG: %s\n"), s); + xfree (s); + return 1; + } + return 0; + case 87: + { + uae_u32 d0, d1; + d0 = emulib_target_getcpurate (ARG1, &d1); + m68k_dreg (regs, 1) = d1; + return d0; + } + } + return 0; +} + +static uae_u32 REGPARAM2 uaelib_demux (TrapContext *context) +{ + uae_u32 v; + + v = uaelib_demux2 (context); + return v; +} + +/* + * Installs the UAE LIBRARY + */ +void emulib_install (void) +{ + uaecptr a; + if (!uae_boot_rom) + return; + a = here (); + org (rtarea_base + 0xFF60); +#if 0 + dw (0x4eb9); + dw ((rtarea_base >> 16) | get_word(rtarea_base + 36)); + dw (get_word(rtarea_base + 38) + 12); +#endif + calltrap (deftrapres (uaelib_demux, 0, _T("uaelib_demux"))); + dw (RTS); + org (a); +} diff --git a/src/zfile.cpp b/src/zfile.cpp index 70718f3a..926f6490 100644 --- a/src/zfile.cpp +++ b/src/zfile.cpp @@ -1,3224 +1,3224 @@ - /* - * UAE - The Un*x Amiga Emulator - * - * routines to handle compressed file automatically - * - * (c) 1996 Samuel Devulder, Tim Gunn - * 2002-2007 Toni Wilen - */ - -#define RECURSIVE_ARCHIVES 1 -//#define ZFILE_DEBUG - -#include "sysconfig.h" -#include "sysdeps.h" - -#include "uae.h" -#include "options.h" -#include "zfile.h" -#include "disk.h" -#include "gui.h" -#include "crc32.h" -#include "fsdb.h" -#include "fsusage.h" -#include "zarchive.h" -#include "diskutil.h" - -#include "archivers/zip/unzip.h" -#include "archivers/dms/pfile.h" -#include "archivers/wrp/warp.h" - -static struct zfile *zlist = 0; - -const TCHAR *uae_archive_extensions[] = { _T("zip"), _T("rar"), _T("7z"), _T("lha"), _T("lzh"), _T("lzx"), _T("tar"), NULL }; - -#define MAX_CACHE_ENTRIES 10 - -struct zdisktrack -{ - void *data; - int len; -}; -struct zdiskimage -{ - int tracks; - struct zdisktrack zdisktracks[2 * 84]; -}; -struct zcache -{ - TCHAR *name; - struct zdiskimage *zd; - void *data; - int size; - struct zcache *next; - time_t tm; -}; -static struct zcache *zcachedata; - -static struct zcache *cache_get (const TCHAR *name) -{ - struct zcache *zc = zcachedata; - while (zc) { - if (!_tcscmp (name, zc->name)) { - zc->tm = time (NULL); - return zc; - } - zc = zc->next; - } - return NULL; -} - -static void zcache_flush (void) -{ -} - -static void zcache_free_data (struct zcache *zc) -{ - int i; - if (zc->zd) { - for (i = 0; i < zc->zd->tracks; i++) { - xfree (zc->zd->zdisktracks[i].data); - } - xfree (zc->zd); - } - xfree (zc->data); - xfree (zc->name); -} - -static void zcache_free (struct zcache *zc) -{ - struct zcache *pl = NULL; - struct zcache *l = zcachedata; - struct zcache *nxt; - - while (l != zc) { - if (l == 0) - return; - pl = l; - l = l->next; - } - if (l) - nxt = l->next; - zcache_free_data (zc); - if (l == 0) - return; - if(!pl) - zcachedata = nxt; - else - pl->next = nxt; -} - -static void zcache_close (void) -{ - struct zcache *zc = zcachedata; - while (zc) { - struct zcache *n = zc->next; - zcache_free_data (zc); - xfree (n); - zc = n; - } -} - -static void zcache_check (void) -{ - int cnt = 0; - struct zcache *zc = zcachedata, *last = NULL; - while (zc) { - last = zc; - zc = zc->next; - cnt++; - } - write_log (_T("CACHE: %d\n"), cnt); - if (cnt >= MAX_CACHE_ENTRIES && last) - zcache_free (last); -} - -static struct zcache *zcache_put (const TCHAR *name, struct zdiskimage *data) -{ - struct zcache *zc; - - zcache_check (); - zc = xcalloc (struct zcache, 1); - zc->next = zcachedata; - zcachedata = zc; - zc->zd = data; - zc->name = my_strdup (name); - zc->tm = time (NULL); - return zc; -} - -static void checkarchiveparent (struct zfile *z) -{ - // unpack completely if opened in PEEK mode - if (z->archiveparent) - archive_unpackzfile (z); -} - -static struct zfile *zfile_create (struct zfile *prev) -{ - struct zfile *z; - - z = xmalloc (struct zfile, 1); - if (!z) - return 0; - memset (z, 0, sizeof *z); - z->next = zlist; - zlist = z; - z->opencnt = 1; - if (prev) { - z->zfdmask = prev->zfdmask; - } - return z; -} - -static void zfile_free (struct zfile *f) -{ - if (f->f) - fclose (f->f); - if (f->deleteafterclose) { - _wunlink (f->name); - write_log (_T("deleted temporary file '%s'\n"), f->name); - } - xfree (f->name); - xfree (f->data); - xfree (f->mode); - xfree (f->userdata); - xfree (f); -} - -void zfile_exit (void) -{ - struct zfile *l; - - while ((l = zlist)) { - zlist = l->next; - zfile_free (l); - } -} - -void zfile_fclose (struct zfile *f) -{ - //write_log (_T("%p\n"), f); - if (!f) - return; - if (f->opencnt < 0) { - write_log (_T("zfile: tried to free already closed filehandle!\n")); - return; - } - f->opencnt--; - if (f->opencnt > 0) - return; - f->opencnt = -100; - if (f->parent) { - f->parent->opencnt--; - if (f->parent->opencnt <= 0) - zfile_fclose (f->parent); - } - if (f->archiveparent) { - zfile_fclose (f->archiveparent); - f->archiveparent = NULL; - } - struct zfile *pl = NULL; - struct zfile *nxt; - struct zfile *l = zlist; - while (l!=f) { - if (l == 0) { - write_log (_T("zfile: tried to free already freed or nonexisting filehandle!\n")); - return; - } - pl = l; - l = l->next; - } - if (l) - nxt = l->next; - zfile_free (f); - if (l == 0) - return; - if(!pl) - zlist = nxt; - else - pl->next = nxt; -} - -static void removeext (TCHAR *s, const char *ext) -{ - if (_tcslen (s) < _tcslen (ext)) - return; - if (_tcsicmp (s + _tcslen (s) - _tcslen (ext), ext) == 0) - s[_tcslen (s) - _tcslen (ext)] = 0; -} - -static bool checkwrite (struct zfile *zf, int *retcode) -{ - if (zfile_needwrite (zf)) { - if (retcode) - *retcode = -1; - return true; - } - return false; -} - -static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00}; -static const char *diskimages[] = { _T("adf"), _T("adz"), _T("ipf"), _T("scp"), _T("fdi"), _T("dms"), _T("wrp"), _T("dsq"), 0 }; - -int zfile_gettype (struct zfile *z) -{ - uae_u8 buf[8]; - TCHAR *ext; - - if (!z || !z->name) - return ZFILE_UNKNOWN; - ext = _tcsrchr (z->name, '.'); - if (ext != NULL) { - int i; - ext++; - for (i = 0; diskimages[i]; i++) { - if (strcasecmp (ext, diskimages[i]) == 0) - return ZFILE_DISKIMAGE; - } - if (strcasecmp (ext, _T("roz")) == 0) - return ZFILE_ROM; - if (strcasecmp (ext, _T("uss")) == 0) - return ZFILE_STATEFILE; - if (strcasecmp (ext, _T("rom")) == 0) - return ZFILE_ROM; - if (strcasecmp (ext, _T("key")) == 0) - return ZFILE_KEY; - if (strcasecmp (ext, _T("nvr")) == 0) - return ZFILE_NVR; - if (strcasecmp (ext, _T("uae")) == 0) - return ZFILE_CONFIGURATION; - if (strcasecmp (ext, _T("cue")) == 0 || strcasecmp (ext, _T("iso")) == 0 || strcasecmp (ext, _T("ccd")) == 0 || strcasecmp (ext, _T("mds")) == 0 || strcasecmp (ext, _T("chd")) == 0) - return ZFILE_CDIMAGE; - } - memset (buf, 0, sizeof (buf)); - zfile_fread (buf, 8, 1, z); - zfile_fseek (z, -8, SEEK_CUR); - if (!memcmp (buf, exeheader, sizeof(buf))) - return ZFILE_DISKIMAGE; - if (!memcmp (buf, "UAE--ADF", 8)) - return ZFILE_DISKIMAGE; - if (!memcmp (buf, "UAE-1ADF", 8)) - return ZFILE_DISKIMAGE; - if (!memcmp (buf, "RDSK", 4)) - return ZFILE_HDFRDB; - if (!memcmp (buf, "DOS", 3)) { - if (z->size < 4 * 1024 * 1024) - return ZFILE_DISKIMAGE; - else - return ZFILE_HDF; - } - if (ext != NULL) { - if (strcasecmp (ext, _T("hdf")) == 0) - return ZFILE_HDF; - if (strcasecmp (ext, _T("hdz")) == 0) - return ZFILE_HDF; - } - return ZFILE_UNKNOWN; -} - -#define VHD_DYNAMIC 3 -#define VHD_FIXED 2 - -STATIC_INLINE uae_u32 gl (uae_u8 *p) -{ - return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); -} - -static uae_u32 vhd_checksum (uae_u8 *p, int offset) -{ - int i; - uae_u32 sum; - - sum = 0; - for (i = 0; i < 512; i++) { - if (offset >= 0 && i >= offset && i < offset + 4) - continue; - sum += p[i]; - } - return ~sum; -} - -struct zfile_vhd -{ - int vhd_type; - uae_u64 virtsize; - uae_u32 vhd_bamoffset; - uae_u32 vhd_blocksize; - uae_u8 *vhd_header, *vhd_sectormap; - uae_u64 vhd_footerblock; - uae_u32 vhd_bamsize; - uae_u64 vhd_sectormapblock; - uae_u32 vhd_bitmapsize; -}; - - -static uae_u64 vhd_fread2 (struct zfile *zf, void *dataptrv, uae_u64 offset, uae_u64 len) -{ - uae_u32 bamoffset; - uae_u32 sectoroffset; - uae_u64 read; - struct zfile *zp = zf->parent; - struct zfile_vhd *zvhd = (struct zfile_vhd*)zf->userdata; - uae_u8 *dataptr = (uae_u8*)dataptrv; - - //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len); - read = 0; - if (offset & 511) - return read; - if (len & 511) - return read; - while (len > 0) { - bamoffset = (offset / zvhd->vhd_blocksize) * 4 + zvhd->vhd_bamoffset; - sectoroffset = gl (zvhd->vhd_header + bamoffset); - if (sectoroffset == 0xffffffff) { - memset (dataptr, 0, 512); - read += 512; - } else { - int bitmapoffsetbits; - int bitmapoffsetbytes; - int sectormapblock; - - bitmapoffsetbits = (offset / 512) % (zvhd->vhd_blocksize / 512); - bitmapoffsetbytes = bitmapoffsetbits / 8; - sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511); - if (zvhd->vhd_sectormapblock != sectormapblock) { - // read sector bitmap - //write_log (_T("BM %08x\n"), sectormapblock); - zfile_fseek (zp, sectormapblock, SEEK_SET); - if (zfile_fread (zvhd->vhd_sectormap, 1, 512, zp) != 512) - return read; - zvhd->vhd_sectormapblock = sectormapblock; - } - // block allocated in bitmap? - if (zvhd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) { - // read data block - int block = sectoroffset * 512 + zvhd->vhd_bitmapsize + bitmapoffsetbits * 512; - //write_log (_T("DB %08x\n"), block); - zfile_fseek (zp, block, SEEK_SET); - if (zfile_fread (dataptr, 1, 512, zp) != 512) - return read; - } else { - memset (dataptr, 0, 512); - } - read += 512; - } - len -= 512; - dataptr += 512; - offset += 512; - } - return read; -} -static uae_s64 vhd_fread (void *data, uae_u64 l1, uae_u64 l2, struct zfile *zf) -{ - uae_u64 size = l1 * l2; - uae_u64 out = 0; - int len = 0; - - if (!l1 || !l2) - return 0; - if ((zf->seek & 511) || (size & 511)) { - uae_u8 tmp[512]; - - if (zf->seek & 511) { - int s; - s = 512 - (zf->seek & 511); - vhd_fread2 (zf, tmp, zf->seek & ~511, 512); - memcpy ((uae_u8*)data + len, tmp + 512 - s, s); - len += s; - out += s; - zf->seek += s; - } - while (size > 0) { - int s = size > 512 ? 512 : size; - vhd_fread2 (zf, tmp, zf->seek, 512); - memcpy ((uae_u8*)data + len, tmp, s); - zf->seek += s; - size -= s; - out += s; - } - } else { - out = vhd_fread2 (zf, data, zf->seek, size); - zf->seek += out; - out /= l1; - } - return out; -} - -static struct zfile *vhd (struct zfile *z) -{ - uae_u8 tmp[512], tmp2[512]; - uae_u32 v; - struct zfile_vhd *zvhd; - uae_u64 fsize; - - zvhd = xcalloc (struct zfile_vhd, 1); - zfile_fseek (z, 0, SEEK_END); - fsize = zfile_ftell (z); - zfile_fseek (z, 0, SEEK_SET); - if (zfile_fread (tmp, 1, 512, z) != 512) - goto nonvhd; - v = gl (tmp + 8); // features - if ((v & 3) != 2) - goto nonvhd; - v = gl (tmp + 8 + 4); // version - if ((v >> 16) != 1) - goto nonvhd; - zvhd->vhd_type = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4); - if (zvhd->vhd_type != VHD_FIXED && zvhd->vhd_type != VHD_DYNAMIC) - goto nonvhd; - v = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4); - if (v == 0) - goto nonvhd; - if (vhd_checksum (tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v) - goto nonvhd; - zfile_fseek (z, fsize - sizeof tmp2, SEEK_SET); - if (zfile_fread (tmp2, 1, 512, z) != 512) - goto end; - if (memcmp (tmp, tmp2, sizeof tmp)) - goto nonvhd; - zvhd->vhd_footerblock = fsize - 512; - zvhd->virtsize = (uae_u64)(gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8)) << 32; - zvhd->virtsize |= gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8 + 4); - if (zvhd->vhd_type == VHD_DYNAMIC) { - uae_u32 size; - zvhd->vhd_bamoffset = gl (tmp + 8 + 4 + 4 + 4); - if (zvhd->vhd_bamoffset == 0 || zvhd->vhd_bamoffset >= fsize) - goto end; - zfile_fseek (z, zvhd->vhd_bamoffset, SEEK_SET); - if (zfile_fread (tmp, 1, 512, z) != 512) - goto end; - v = gl (tmp + 8 + 8 + 8 + 4 + 4 + 4); - if (vhd_checksum (tmp, 8 + 8 + 8 + 4 + 4 + 4) != v) - goto end; - v = gl (tmp + 8 + 8 + 8); - if ((v >> 16) != 1) - goto end; - zvhd->vhd_blocksize = gl (tmp + 8 + 8 + 8 + 4 + 4); - zvhd->vhd_bamoffset = gl (tmp + 8 + 8 + 4); - zvhd->vhd_bamsize = (((zvhd->virtsize + zvhd->vhd_blocksize - 1) / zvhd->vhd_blocksize) * 4 + 511) & ~511; - size = zvhd->vhd_bamoffset + zvhd->vhd_bamsize; - zvhd->vhd_header = xmalloc (uae_u8, size); - zfile_fseek (z, 0, SEEK_SET); - if (zfile_fread (zvhd->vhd_header, 1, size, z) != size) - goto end; - zvhd->vhd_sectormap = xmalloc (uae_u8, 512); - zvhd->vhd_sectormapblock = -1; - zvhd->vhd_bitmapsize = ((zvhd->vhd_blocksize / (8 * 512)) + 511) & ~511; - } - z = zfile_fopen_parent (z, NULL, 0, zvhd->virtsize); - z->useparent = 0; - z->dataseek = 1; - z->userdata = zvhd; - z->zfileread = vhd_fread; - write_log (_T("%s is VHD %s image, virtual size=%lldK\n"), - zfile_getname (z), - zvhd->vhd_type == 2 ? _T("fixed") : _T("dynamic"), - zvhd->virtsize / 1024); - return z; -nonvhd: -end: - return z; -} - -static struct zfile *zfile_gunzip (struct zfile *z, int *retcode) -{ - uae_u8 header[2 + 1 + 1 + 4 + 1 + 1]; - z_stream zs; - int i, size, ret, first; - uae_u8 flags; - uae_s64 offset; - TCHAR name[MAX_DPATH]; - uae_u8 buffer[8192]; - struct zfile *z2; - uae_u8 b; - - if (checkwrite (z, retcode)) - return NULL; - _tcscpy (name, z->name); - memset (&zs, 0, sizeof (zs)); - memset (header, 0, sizeof (header)); - zfile_fread (header, sizeof (header), 1, z); - flags = header[3]; - if (header[0] != 0x1f && header[1] != 0x8b) - return NULL; - if (flags & 2) /* multipart not supported */ - return NULL; - if (flags & 32) /* encryption not supported */ - return NULL; - if (flags & 4) { /* skip extra field */ - zfile_fread (&b, 1, 1, z); - size = b; - zfile_fread (&b, 1, 1, z); - size |= b << 8; - zfile_fseek (z, size + 2, SEEK_CUR); - } - - if (flags & 8) { /* get original file name */ - uae_char aname[MAX_DPATH]; - i = 0; - do { - zfile_fread (aname + i, 1, 1, z); - } while (i < MAX_DPATH - 1 && aname[i++]); - aname[i] = 0; - au_copy (name, MAX_DPATH, aname); - } - if (flags & 16) { /* skip comment */ - i = 0; - do { - b = 0; - zfile_fread (&b, 1, 1, z); - } while (b); - } - removeext (name, _T(".gz")); - offset = zfile_ftell (z); - zfile_fseek (z, -4, SEEK_END); - zfile_fread (&b, 1, 1, z); - size = b; - zfile_fread (&b, 1, 1, z); - size |= b << 8; - zfile_fread (&b, 1, 1, z); - size |= b << 16; - zfile_fread (&b, 1, 1, z); - size |= b << 24; - if (size < 8 || size > 256 * 1024 * 1024) /* safety check */ - return NULL; - zfile_fseek (z, offset, SEEK_SET); - z2 = zfile_fopen_empty (z, name, size); - if (!z2) - return NULL; - zs.next_out = z2->data; - zs.avail_out = size; - first = 1; - do { - zs.next_in = buffer; - zs.avail_in = zfile_fread (buffer, 1, sizeof (buffer), z); - if (first) { - if (inflateInit2_ (&zs, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream)) != Z_OK) - break; - first = 0; - } - ret = inflate (&zs, 0); - } while (ret == Z_OK); - inflateEnd (&zs); - if (ret != Z_STREAM_END || first != 0) { - zfile_fclose (z2); - return NULL; - } - zfile_fclose (z); - return z2; -} -struct zfile *zfile_gunzip (struct zfile *z) -{ - return zfile_gunzip (z, NULL); -} - -static void truncate880k (struct zfile *z) -{ - int i; - uae_u8 *b; - - if (z == NULL || z->data == NULL) - return; - if (z->size < 880 * 512 * 2) { - int size = 880 * 512 * 2 - z->size; - b = xcalloc (uae_u8, size); - zfile_fwrite (b, size, 1, z); - xfree (b); - return; - } - for (i = 880 * 512 * 2; i < z->size; i++) { - if (z->data[i]) - return; - } - z->size = 880 * 512 * 2; -} - -static struct zfile *extadf (struct zfile *z, int index, int *retcode) -{ - int i, r; - struct zfile *zo; - uae_u16 *mfm; - uae_u16 *amigamfmbuffer; - uae_u8 writebuffer_ok[32], *outbuf; - int tracks, len, offs, pos; - uae_u8 buffer[2 + 2 + 4 + 4]; - int outsize; - TCHAR newname[MAX_DPATH]; - TCHAR *ext; - int cantrunc = 0; - int done = 0; - - if (index > 1) - return NULL; - - mfm = xcalloc (uae_u16, 32000 / 2); - amigamfmbuffer = xcalloc (uae_u16, 32000 / 2); - outbuf = xcalloc (uae_u8, 16384); - - zfile_fread (buffer, 1, 8, z); - zfile_fread (buffer, 1, 4, z); - tracks = buffer[2] * 256 + buffer[3]; - offs = 8 + 2 + 2 + tracks * (2 + 2 + 4 + 4); - - _tcscpy (newname, zfile_getname (z)); - ext = _tcsrchr (newname, '.'); - if (ext) { - _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".std.adf")); - } else { - _tcscat (newname, _T(".std.adf")); - } - if (index > 0) - _tcscpy (newname + _tcslen (newname) - 4, _T(".ima")); - - zo = zfile_fopen_empty (z, newname, 0); - if (!zo) - goto end; - - if (retcode) - *retcode = 1; - pos = 12; - outsize = 0; - for (i = 0; i < tracks; i++) { - int type, bitlen; - - zfile_fseek (z, pos, SEEK_SET); - zfile_fread (buffer, 2 + 2 + 4 + 4, 1, z); - pos = zfile_ftell (z); - type = buffer[2] * 256 + buffer[3]; - len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7]; - bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11]; - - zfile_fseek (z, offs, SEEK_SET); - if (type == 1) { - zfile_fread (mfm, len, 1, z); - memset (writebuffer_ok, 0, sizeof writebuffer_ok); - memset (outbuf, 0, 16384); - if (index == 0) { - r = isamigatrack (amigamfmbuffer, (uae_u8*)mfm, len, outbuf, writebuffer_ok, i, &outsize); - if (r < 0 && i == 0) { - zfile_seterror (_T("'%s' is not AmigaDOS formatted"), zo->name); - goto end; - } - if (i == 0) - done = 1; - } else { - r = ispctrack (amigamfmbuffer, (uae_u8*)mfm, len, outbuf, writebuffer_ok, i, &outsize); - if (r < 0 && i == 0) { - zfile_seterror (_T("'%s' is not PC formatted"), zo->name); - goto end; - } - if (i == 0) - done = 1; - } - } else { - outsize = 512 * 11; - if (bitlen / 8 > 18000) - outsize *= 2; - zfile_fread (outbuf, outsize, 1, z); - cantrunc = 1; - if (index == 0) - done = 1; - } - zfile_fwrite (outbuf, outsize, 1, zo); - - offs += len; - - } - if (done == 0) - goto end; - zfile_fclose (z); - xfree (mfm); - xfree (amigamfmbuffer); - if (cantrunc) - truncate880k (zo); - return zo; -end: - zfile_fclose (zo); - xfree (mfm); - xfree (amigamfmbuffer); - return NULL; -} - -#ifdef CAPS -#include "caps/caps_win32.h" -static struct zfile *ipf (struct zfile *z, int index, int *retcode) -{ - int i, j, r; - struct zfile *zo; - TCHAR *orgname = zfile_getname (z); - TCHAR *ext = _tcsrchr (orgname, '.'); - TCHAR newname[MAX_DPATH]; - uae_u16 *amigamfmbuffer; - uae_u8 writebuffer_ok[32]; - int tracks, len; - int outsize; - int startpos = 0; - uae_u8 *outbuf; - uae_u8 tmp[12]; - struct zcache *zc; - - if (checkwrite (z, retcode)) - return NULL; - - if (index > 2) - return NULL; - - zc = cache_get (z->name); - if (!zc) { - uae_u16 *mfm; - struct zdiskimage *zd; - if (!caps_loadimage (z, 0, &tracks)) - return NULL; - mfm = xcalloc (uae_u16, 32000 / 2); - zd = xcalloc (struct zdiskimage, 1); - zd->tracks = tracks; - for (i = 0; i < tracks; i++) { - uae_u8 *buf, *p; - int mrev, gapo; - caps_loadtrack (mfm, NULL, 0, i, &len, &mrev, &gapo, NULL, true); - //write_log (_T("%d: %d %d %d\n"), i, mrev, gapo, len); - len /= 8; - buf = p = xmalloc (uae_u8, len); - for (j = 0; j < len / 2; j++) { - uae_u16 v = mfm[j]; - *p++ = v >> 8; - *p++ = v; - } - zd->zdisktracks[i].data = buf; - zd->zdisktracks[i].len = len; - } - caps_unloadimage (0); - zc = zcache_put (z->name, zd); - } - - outbuf = xcalloc (uae_u8, 16384); - amigamfmbuffer = xcalloc (uae_u16, 32000 / 2); - if (ext) { - _tcscpy (newname, orgname); - _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf")); - } else { - _tcscat (newname, _T(".adf")); - } - if (index == 1) - _tcscpy (newname + _tcslen (newname) - 4, _T(".ima")); - if (index == 2) - _tcscpy (newname + _tcslen (newname) - 4, _T(".ext.adf")); - - zo = zfile_fopen_empty (z, newname, 0); - if (!zo) - goto end; - - if (retcode) - *retcode = 1; - - tracks = zc->zd->tracks; - - if (index > 1) { - zfile_fwrite ("UAE-1ADF", 8, 1, zo); - tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */ - tmp[2] = 0; tmp[3] = tracks; /* number of tracks */ - zfile_fwrite (tmp, 4, 1, zo); - memset (tmp, 0, sizeof tmp); - tmp[2] = 0; tmp[3] = 1; /* track type */ - startpos = zfile_ftell (zo); - for (i = 0; i < tracks; i++) - zfile_fwrite (tmp, sizeof tmp, 1, zo); - } - - outsize = 0; - for (i = 0; i < tracks; i++) { - uae_u8 *p = (uae_u8*)zc->zd->zdisktracks[i].data; - len = zc->zd->zdisktracks[i].len; - memset (writebuffer_ok, 0, sizeof writebuffer_ok); - memset (outbuf, 0, 16384); - if (index == 0) { - r = isamigatrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize); - if (r < 0 && i == 0) { - zfile_seterror (_T("'%s' is not AmigaDOS formatted"), orgname); - goto end; - } - zfile_fwrite (outbuf, 1, outsize, zo); - } else if (index == 1) { - r = ispctrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize); - if (r < 0 && i == 0) { - zfile_seterror (_T("'%s' is not PC formatted"), orgname); - goto end; - } - zfile_fwrite (outbuf, outsize, 1, zo); - } else { - int pos = zfile_ftell (zo); - int maxlen = len > 12798 ? len : 12798; - int lenb = len * 8; - - if (maxlen & 1) - maxlen++; - zfile_fseek (zo, startpos + i * 12 + 4, SEEK_SET); - tmp[4] = 0; tmp[5] = 0; tmp[6] = maxlen >> 8; tmp[7] = maxlen; - tmp[8] = lenb >> 24; tmp[9] = lenb >> 16; tmp[10] = lenb >> 8; tmp[11] = lenb; - zfile_fwrite (tmp + 4, 2, 4, zo); - zfile_fseek (zo, pos, SEEK_SET); - zfile_fwrite (p, 1, len, zo); - if (maxlen > len) - zfile_fwrite (outbuf, 1, maxlen - len, zo); - } - } - zfile_fclose (z); - xfree (amigamfmbuffer); - xfree (outbuf); - if (index == 0) - truncate880k (zo); - return zo; -end: - zfile_fclose (zo); - xfree (amigamfmbuffer); - xfree (outbuf); - return NULL; -} -#endif - -#ifdef A_LZX -static struct zfile *dsq (struct zfile *z, int lzx, int *retcode) -{ - struct zfile *zi = NULL; - struct zvolume *zv = NULL; - - if (checkwrite (z, retcode)) - return NULL; - if (lzx) { - zv = archive_directory_lzx (z); - if (zv) { - if (zv->root.child) - zi = archive_access_lzx (zv->root.child); - } - } else { - zi = z; - } - if (zi) { - uae_u8 *buf = zfile_getdata (zi, 0, -1); - if (!memcmp (buf, "PKD\x13", 4) || !memcmp (buf, "PKD\x11", 4)) { - TCHAR *fn; - int sectors = buf[18]; - int reserved = buf[15]; - int blocks = (buf[6] << 8) | buf[7]; - int blocksize = (buf[10] << 8) | buf[11]; - struct zfile *zo; - int size = blocks * blocksize; - int off; - int i; - uae_u8 *bitmap = NULL; - uae_u8 *nullsector; - - nullsector = xcalloc (uae_u8, blocksize); - sectors /= 2; - if (buf[3] == 0x13) { - off = 52; - if (buf[off - 1] == 1) { - bitmap = &buf[off]; - off += (blocks + 7) / 8; - } else if (buf[off - 1] > 1) { - write_log (_T("unknown DSQ extra header type %d\n"), buf[off - 1]); - } - } else { - off = 32; - } - - // some Amiga disk images are smaller than full adf for some reason - if (sectors == 11 && size < 1760 * 512) - size = 1760 * 512; - - if (zfile_getfilename (zi) && _tcslen (zfile_getfilename (zi))) { - fn = xmalloc (TCHAR, (_tcslen (zfile_getfilename (zi)) + 5)); - _tcscpy (fn, zfile_getfilename (zi)); - _tcscat (fn, _T(".adf")); - } else { - fn = my_strdup (_T("dsq.adf")); - } - zo = zfile_fopen_empty (z, fn, size); - xfree (fn); - int seccnt = 0; - for (i = 0; i < blocks; i++) { - int bmoff = i - 2; - int boff = -1; - uae_u32 mask = 0; - if (bitmap) { - boff = (bmoff / 32) * 4; - mask = (bitmap[boff] << 24) | (bitmap[boff + 1] << 16) | (bitmap[boff + 2] << 8) | (bitmap[boff + 3]); - } - if (bmoff >= 0 && boff >= 0 && (mask & (1 << (bmoff & 31)))) { - zfile_fwrite (nullsector, blocksize, 1, zo); - } else { - zfile_fwrite (buf + off, blocksize, 1, zo); - off += blocksize; - seccnt++; - } - if ((i % sectors) == sectors - 1) { - off += seccnt * 16; - seccnt = 0; - } - } - zfile_fclose_archive (zv); - zfile_fclose (z); - xfree (buf); - xfree (nullsector); - return zo; - } - xfree (buf); - } - if (lzx) - zfile_fclose (zi); - return z; -} -#endif - -#ifdef A_WRP -static struct zfile *wrp (struct zfile *z, int *retcode) -{ - if (zfile_needwrite (z)) { - if (retcode) - *retcode = -1; - return NULL; - } - return unwarp (z); -} -#endif - -#ifdef A_DMS -static struct zfile *dms (struct zfile *z, int index, int *retcode) -{ - int ret; - struct zfile *zo; - TCHAR *orgname = zfile_getname (z); - TCHAR *ext = _tcsrchr (orgname, '.'); - TCHAR newname[MAX_DPATH]; - static int recursive; - int i; - struct zfile *zextra[DMS_EXTRA_SIZE] = { 0 }; - - if (checkwrite (z, retcode)) - return NULL; - if (recursive) - return NULL; - if (ext) { - _tcscpy (newname, orgname); - _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf")); - } else { - _tcscat (newname, _T(".adf")); - } - - zo = zfile_fopen_empty (z, newname, 1760 * 512); - if (!zo) - return NULL; - ret = DMS_Process_File (z, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0, 0, zextra); - if (ret == NO_PROBLEM || ret == DMS_FILE_END) { - int off = zfile_ftell (zo); - if (off >= 1760 * 512 / 3 && off <= 1760 * 512 * 3 / 4) { // possible split dms? - if (_tcslen (orgname) > 5) { - TCHAR *s = orgname + _tcslen (orgname) - 5; - if (!_tcsicmp (s, _T("a.dms"))) { - TCHAR *fn2 = my_strdup (orgname); - struct zfile *z2; - fn2[_tcslen (fn2) - 5]++; - recursive++; - z2 = zfile_fopen (fn2, _T("rb"), z->zfdmask); - recursive--; - if (z2) { - ret = DMS_Process_File (z2, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0, 1, NULL); - zfile_fclose (z2); - } - xfree (fn2); - } - } - } - zfile_fseek (zo, 0, SEEK_SET); - if (index > 0) { - zfile_fclose (zo); - zo = NULL; - for (i = 0; i < DMS_EXTRA_SIZE && zextra[i]; i++); - if (index > i) - goto end; - zo = zextra[index - 1]; - zextra[index - 1] = NULL; - } - if (retcode) - *retcode = 1; - zfile_fclose (z); - z = NULL; - - } else { - zfile_fclose (zo); - zo = NULL; - } -end: - for (i = 0; i < DMS_EXTRA_SIZE; i++) - zfile_fclose (zextra[i]); - return zo; -} -#endif - -const TCHAR *uae_ignoreextensions[] = - { _T(".gif"), _T(".jpg"), _T(".png"), _T(".xml"), _T(".pdf"), _T(".txt"), 0 }; -const TCHAR *uae_diskimageextensions[] = - { _T(".adf"), _T(".adz"), _T(".ipf"), _T(".scp"), _T(".fdi"), _T(".exe"), _T(".dms"), _T(".wrp"), _T(".dsq"), 0 }; - -int zfile_is_ignore_ext(const TCHAR *name) -{ - int i; - const TCHAR *ext; - - ext = _tcsrchr (name, '.'); - if (!ext) - return 0; - for (i = 0; uae_ignoreextensions[i]; i++) { - if (!strcasecmp (uae_ignoreextensions[i], ext)) - return 1; - } - return 0; -} - -int zfile_is_diskimage (const TCHAR *name) -{ - int i; - - const TCHAR *ext = _tcsrchr (name, '.'); - if (!ext) - return 0; - i = 0; - while (uae_diskimageextensions[i]) { - if (!strcasecmp (ext, uae_diskimageextensions[i])) - return HISTORY_FLOPPY; - i++; - } - if (!_tcsicmp (ext, _T(".cue"))) - return HISTORY_CD; - return -1; -} - -static const TCHAR *archive_extensions[] = { - _T("7z"), _T("rar"), _T("zip"), _T("lha"), _T("lzh"), _T("lzx"), - _T("adf"), _T("adz"), _T("dsq"), _T("dms"), _T("ipf"), _T("fdi"), _T("wrp"), _T("ima"), - _T("hdf"), _T("tar"), - NULL -}; -static const TCHAR *plugins_7z[] = { _T("7z"), _T("rar"), _T("zip"), _T("lha"), _T("lzh"), _T("lzx"), _T("adf"), _T("dsq"), _T("hdf"), _T("tar"), NULL }; -static const uae_char *plugins_7z_x[] = { "7z", "Rar!", "MK", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -static const int plugins_7z_t[] = { - ArchiveFormat7Zip, ArchiveFormatRAR, ArchiveFormatZIP, ArchiveFormatLHA, ArchiveFormatLHA, ArchiveFormatLZX, - ArchiveFormatADF, ArchiveFormatADF, ArchiveFormatADF, ArchiveFormatTAR -}; -static const int plugins_7z_m[] = { - ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, - ZFD_ADF, ZFD_ADF, ZFD_ADF, ZFD_ARCHIVE -}; - -int iszip (struct zfile *z, int mask) -{ - TCHAR *name = z->name; - TCHAR *ext = _tcsrchr (name, '.'); - uae_u8 header[32]; - int i; - - if (!ext) - return 0; - memset (header, 0, sizeof (header)); - zfile_fseek (z, 0, SEEK_SET); - zfile_fread (header, sizeof (header), 1, z); - zfile_fseek (z, 0, SEEK_SET); - - if (mask & ZFD_ARCHIVE) { - if (!strcasecmp (ext, _T(".zip")) || !strcasecmp (ext, _T(".rp9"))) { - if(header[0] == 'P' && header[1] == 'K') - return ArchiveFormatZIP; - return 0; - } - } - if (mask & ZFD_ARCHIVE) { - if (!strcasecmp (ext, _T(".7z"))) { - if(header[0] == '7' && header[1] == 'z') - return ArchiveFormat7Zip; - return 0; - } - if (!strcasecmp (ext, _T(".rar"))) { - if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!') - return ArchiveFormatRAR; - return 0; - } - if (!strcasecmp (ext, _T(".lha")) || !strcasecmp (ext, _T(".lzh"))) { - if(header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-') - return ArchiveFormatLHA; - return 0; - } - if (!strcasecmp (ext, _T(".lzx"))) { - if(header[0] == 'L' && header[1] == 'Z' && header[2] == 'X') - return ArchiveFormatLZX; - return 0; - } - } - if (mask & ZFD_ADF) { - if (!strcasecmp (ext, _T(".adf"))) { - if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) - return ArchiveFormatADF; - if (isfat (header)) - return ArchiveFormatFAT; - return 0; - } - if (!strcasecmp (ext, _T(".ima"))) { - if (isfat (header)) - return ArchiveFormatFAT; - } - } - if (mask & ZFD_HD) { - if (!strcasecmp (ext, _T(".hdf"))) { - if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) - return ArchiveFormatADF; - if (header[0] == 'S' && header[1] == 'F' && header[2] == 'S') - return ArchiveFormatADF; - if (header[0] == 'R' && header[1] == 'D' && header[2] == 'S' && header[3] == 'K') - return ArchiveFormatRDB; - if (isfat (header)) - return ArchiveFormatFAT; - return 0; - } - } -#if defined(ARCHIVEACCESS) - for (i = 0; plugins_7z_x[i]; i++) { - if ((plugins_7z_m[i] & mask) && plugins_7z_x[i] && !strcasecmp (ext + 1, plugins_7z[i]) && - !memcmp (header, plugins_7z_x[i], strlen (plugins_7z_x[i]))) - return plugins_7z_t[i]; - } -#endif - return 0; -} -int iszip (struct zfile *z) -{ - return iszip (z, ZFD_NORMAL); -} - -struct zfile *zuncompress (struct znode *parent, struct zfile *z, int dodefault, int mask, int *retcode, int index) -{ - TCHAR *name = z->name; - TCHAR *ext = NULL; - uae_u8 header[32]; - int i; - - if (retcode) - *retcode = 0; - if (!mask) - return NULL; - if (name) { - ext = _tcsrchr (name, '.'); - if (ext) - ext++; - } - - if (ext != NULL) { - if (mask & ZFD_ARCHIVE) { - if (strcasecmp (ext, _T("7z")) == 0) - return archive_access_select (parent, z, ArchiveFormat7Zip, dodefault, retcode, index); - if (strcasecmp (ext, _T("zip")) == 0) - return archive_access_select (parent, z, ArchiveFormatZIP, dodefault, retcode, index); - if (strcasecmp (ext, _T("lha")) == 0 || strcasecmp (ext, _T("lzh")) == 0) - return archive_access_select (parent, z, ArchiveFormatLHA, dodefault, retcode, index); - if (strcasecmp (ext, _T("lzx")) == 0) - return archive_access_select (parent, z, ArchiveFormatLZX, dodefault, retcode, index); - if (strcasecmp (ext, _T("rar")) == 0) - return archive_access_select (parent, z, ArchiveFormatRAR, dodefault, retcode, index); - if (strcasecmp (ext, _T("tar")) == 0) - return archive_access_select (parent, z, ArchiveFormatTAR, dodefault, retcode, index); - } - if (mask & ZFD_UNPACK) { - if (index == 0) { - if (strcasecmp (ext, _T("gz")) == 0) - return zfile_gunzip (z, retcode); - if (strcasecmp (ext, _T("adz")) == 0) - return zfile_gunzip (z, retcode); - if (strcasecmp (ext, _T("roz")) == 0) - return zfile_gunzip (z, retcode); - if (strcasecmp (ext, _T("hdz")) == 0) - return zfile_gunzip (z, retcode); -#ifdef A_WRP - if (strcasecmp (ext, _T("wrp")) == 0) - return wrp (z, retcode); -#endif - } -#ifdef A_DMS - if (strcasecmp (ext, _T("dms")) == 0) - return dms (z, index, retcode); -#endif - } - if (mask & ZFD_RAWDISK) { -#ifdef CAPS - if (strcasecmp (ext, _T("ipf")) == 0) - return ipf (z, index, retcode); -#endif - if (mask & (ZFD_RAWDISK_PC | ZFD_RAWDISK_AMIGA)) - return NULL; - } -#if defined(ARCHIVEACCESS) - if (index == 0) { - for (i = 0; plugins_7z_x[i]; i++) { - if ((plugins_7z_t[i] & mask) && strcasecmp (ext, plugins_7z[i]) == 0) - return archive_access_arcacc_select (z, plugins_7z_t[i], retcode); - } - } -#endif - } - memset (header, 0, sizeof (header)); - zfile_fseek (z, 0, SEEK_SET); - zfile_fread (header, sizeof (header), 1, z); - zfile_fseek (z, 0, SEEK_SET); - if (!memcmp (header, "conectix", 8)) { - if (index > 0) - return NULL; - return vhd (z); - } - if (mask & ZFD_UNPACK) { - if (index == 0) { - if (header[0] == 0x1f && header[1] == 0x8b) - return zfile_gunzip (z, retcode); -#ifdef A_LZX - if (header[0] == 'P' && header[1] == 'K' && header[2] == 'D') - return dsq (z, 0, retcode); -#endif - } -#ifdef A_DMS - if (header[0] == 'D' && header[1] == 'M' && header[2] == 'S' && header[3] == '!') - return dms (z, index, retcode); -#endif - } - if (mask & ZFD_RAWDISK) { -#ifdef CAPS - if (header[0] == 'C' && header[1] == 'A' && header[2] == 'P' && header[3] == 'S') - return ipf (z, index, retcode); -#endif - if (!memcmp (header, "UAE-1ADF", 8)) - return extadf (z, index, retcode); - } - if (index > 0) - return NULL; - if (mask & ZFD_ARCHIVE) { - if (header[0] == 'P' && header[1] == 'K') - return archive_access_select (parent, z, ArchiveFormatZIP, dodefault, retcode, index); - if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!') - return archive_access_select (parent, z, ArchiveFormatRAR, dodefault, retcode, index); - if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X') - return archive_access_select (parent, z, ArchiveFormatLZX, dodefault, retcode, index); - if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-') - return archive_access_select (parent, z, ArchiveFormatLHA, dodefault, retcode, index); - } - if (mask & ZFD_ADF) { - if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) - return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index); - if (header[0] == 'S' && header[1] == 'F' && header[2] == 'S') - return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index); - if (isfat (header)) - return archive_access_select (parent, z, ArchiveFormatFAT, dodefault, retcode, index); - } - - if (ext) { - if (mask & ZFD_UNPACK) { -#ifdef A_LZX - if (strcasecmp (ext, _T("dsq")) == 0) - return dsq (z, 1, retcode); -#endif - } - if (mask & ZFD_ADF) { - if (strcasecmp (ext, _T("adf")) == 0 && !memcmp (header, "DOS", 3)) - return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index); - } - } - return NULL; -} - -#ifdef SINGLEFILE -extern uae_u8 singlefile_data[]; - -static struct zfile *zfile_opensinglefile(struct zfile *l) -{ - uae_u8 *p = singlefile_data; - int size, offset; - TCHAR tmp[256], *s; - - _tcscpy (tmp, l->name); - s = tmp + _tcslen (tmp) - 1; - while (*s != 0 && *s != '/' && *s != '\\') - s--; - if (s > tmp) - s++; - write_log (_T("loading from singlefile: '%s'\n"), tmp); - while (*p++); - offset = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0); - p += 4; - for (;;) { - size = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0); - if (!size) - break; - if (!strcmpi (tmp, p + 4)) { - l->data = singlefile_data + offset; - l->size = size; - write_log (_T("found, size %d\n"), size); - return l; - } - offset += size; - p += 4; - p += _tcslen (p) + 1; - } - write_log (_T("not found\n")); - return 0; -} -#endif - -static struct zfile *zfile_fopen_nozip (const TCHAR *name, const TCHAR *mode) -{ - struct zfile *l; - FILE *f; - - if(*name == '\0') - return NULL; - l = zfile_create (NULL); - l->name = my_strdup (name); - l->mode = my_strdup (mode); - f = _tfopen (name, mode); - if (!f) { - zfile_fclose (l); - return 0; - } - l->f = f; - return l; -} - - -static struct zfile *openzip (const TCHAR *pname) -{ - int i, j; - TCHAR v; - TCHAR name[MAX_DPATH]; - TCHAR zippath[MAX_DPATH]; - - zippath[0] = 0; - _tcscpy (name, pname); - i = _tcslen (name) - 2; - while (i > 0) { - if ((name[i] == '/' || name[i] == '\\') && i > 4) { - v = name[i]; - name[i] = 0; - for (j = 0; plugins_7z[j]; j++) { - int len = _tcslen (plugins_7z[j]); - if (name[i - len - 1] == '.' && !strcasecmp (name + i - len, plugins_7z[j])) { - struct zfile *f = zfile_fopen_nozip (name, _T("rb")); - if (f) { - f->zipname = my_strdup(name + i + 1); - return f; - } - break; - } - } - name[i] = v; - } - i--; - } - return 0; -} - -static bool writeneeded (const TCHAR *mode) -{ - return _tcschr (mode, 'w') || _tcschr (mode, 'a') || _tcschr (mode, '+') || _tcschr (mode, 't'); -} -bool zfile_needwrite (struct zfile *zf) -{ - if (!zf->mode) - return false; - return writeneeded (zf->mode); -} - -static struct zfile *zfile_fopen_2 (const TCHAR *name, const TCHAR *mode, int mask) -{ - struct zfile *l; - FILE *f; - - if( *name == '\0' ) - return NULL; -#ifdef SINGLEFILE - if (zfile_opensinglefile (l)) - return l; -#endif - l = openzip (name); - if (l) { - if (writeneeded (mode)) { - zfile_fclose (l); - return 0; - } - l->zfdmask = mask; - } else { - struct mystat st; - l = zfile_create (NULL); - l->mode = my_strdup (mode); - l->name = my_strdup (name); - l->zfdmask = mask; - if (!_tcsicmp (mode, _T("r"))) { - f = my_opentext (l->name); - l->textmode = 1; - } else { - f = _tfopen (l->name, mode); - } - if (!f) { - zfile_fclose (l); - return 0; - } - if (my_stat (l->name, &st)) - l->size = st.size; - l->f = f; - } - return l; -} - -#define AF _T("%AMIGAFOREVERDATA%") - -static void manglefilename(TCHAR *out, const TCHAR *in) -{ - int i; - - out[0] = 0; - if (!strncasecmp(in, AF, _tcslen(AF))) - _tcscpy (out, start_path_data); - if ((in[0] == '/' || in[0] == '\\') || (_tcslen(in) > 3 && in[1] == ':' && in[2] == '\\')) - out[0] = 0; - _tcscat(out, in); - for (i = 0; i < _tcslen (out); i++) { - // remove \\ or // in the middle of path - if ((out[i] == '/' || out[i] == '\\') && (out[i + 1] == '/' || out[i + 1] == '\\') && i > 0) { - memmove (out + i, out + i + 1, (_tcslen (out + i) + 1) * sizeof (TCHAR)); - i--; - continue; - } - } -} - -int zfile_zopen (const TCHAR *name, zfile_callback zc, void *user) -{ - struct zfile *l; - int ztype; - TCHAR path[MAX_DPATH]; - - manglefilename(path, name); - l = zfile_fopen_2 (path, _T("rb"), ZFD_NORMAL); - if (!l) - return 0; - ztype = iszip (l); - if (ztype == 0) - zc (l, user); - else - archive_access_scan (l, zc, user, ztype); - zfile_fclose (l); - return 1; -} - -/* - * fopen() for a compressed file - */ -static struct zfile *zfile_fopen_x (const TCHAR *name, const TCHAR *mode, int mask, int index) -{ - int cnt = 10; - struct zfile *l, *l2; - TCHAR path[MAX_DPATH]; - - if (_tcslen (name) == 0) - return NULL; - manglefilename(path, name); - l = zfile_fopen_2 (path, mode, mask); - if (!l) - return 0; - l2 = NULL; - while (cnt-- > 0) { - int rc; - zfile_fseek (l, 0, SEEK_SET); - l2 = zuncompress (NULL, l, 0, mask, &rc, index); - if (!l2) { - if (rc < 0) { - zfile_fclose (l); - return NULL; - } - zfile_fseek (l, 0, SEEK_SET); - break; - } else { - if (l2->parent == l) - l->opencnt--; - } - l = l2; - } - return l; -} - -#ifdef _WIN32 -static int isinternetfile (const TCHAR *name) -{ - if (!_tcsnicmp (name, _T("http://"), 7) || !_tcsnicmp (name, _T("https://"), 8)) - return 1; - if (!_tcsnicmp (name, _T("ftp://"), 6)) - return -1; - return 0; -} -#include -#define INETBUFFERLEN 1000000 -static struct zfile *zfile_fopen_internet (const TCHAR *name, const TCHAR *mode, int mask) -{ - static HINTERNET hi; - HINTERNET i = NULL; - TCHAR tmp[MAX_DPATH]; - DWORD ierr = 0; - DWORD outbuf = sizeof tmp / sizeof (TCHAR); - uae_u8 *data = 0; - int bufferlen = INETBUFFERLEN; - int datalen; - DWORD didread; - struct zfile *zf = NULL; - - if (_tcschr (mode, 'w') || _tcschr (mode, 'a')) - return NULL; - tmp[0] = 0; - if (!hi) { - hi = InternetOpen (WINUAEAPPNAME, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0); - if (hi == NULL) { - write_log (_T("InternetOpen() failed, %d\n"), GetLastError ()); - return NULL; - } - } - i = InternetOpenUrl (hi, name, NULL, 0, INTERNET_FLAG_NO_COOKIES, 0); - if (i == NULL) { - DWORD err = GetLastError (); - if (err == ERROR_INTERNET_EXTENDED_ERROR) - InternetGetLastResponseInfo (&ierr, tmp, &outbuf); - write_log (_T("InternetOpenUrl(%s) failed %d (%d,%s)\n"), name, err, ierr, tmp); - goto end; - } - - if (isinternetfile (name) > 0) { - DWORD statuscode; - DWORD hindex = 0; - DWORD size = sizeof statuscode; - if (!HttpQueryInfo (i, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &statuscode, &size, &hindex)) { - DWORD err = GetLastError (); - write_log (_T("HttpQueryInfo(%s) failed %d\n"), name, err); - goto end; - } - if (statuscode != 200) { - write_log (_T("HttpQueryInfo(%s)=%d\n"), name, statuscode); - goto end; - } - } - - if (mask & ZFD_CHECKONLY) { - zf = zfile_create (NULL); - goto end; - } - - datalen = 0; - data = xmalloc (uae_u8, bufferlen); - for (;;) { - if (!InternetReadFile (i, data + datalen, INETBUFFERLEN, &didread)) { - DWORD err = GetLastError (); - if (err == ERROR_INTERNET_EXTENDED_ERROR) - InternetGetLastResponseInfo (&ierr, tmp, &outbuf); - write_log (_T("InternetReadFile(%s) failed %d (%d,%s)\n"), name, err, ierr, tmp); - break; - } - if (didread == 0) - break; - datalen += didread; - if (datalen > bufferlen - INETBUFFERLEN) { - bufferlen += INETBUFFERLEN; - data = xrealloc (uae_u8, data, bufferlen); - if (!data) { - datalen = 0; - break; - } - } - } - if (datalen > 0) { - zf = zfile_create (NULL); - if (zf) { - zf->size = datalen; - zf->data = data; - data = NULL; - } - } -end: - if (i) - InternetCloseHandle (i); - free (data); - return zf; -} -#endif - -static struct zfile *zfile_fopenx2 (const TCHAR *name, const TCHAR *mode, int mask, int index) -{ - struct zfile *f; - TCHAR tmp[MAX_DPATH]; - -#ifdef _WIN32 - if (isinternetfile (name)) - return zfile_fopen_internet (name, mode, mask); -#endif - f = zfile_fopen_x (name, mode, mask, index); - if (f) - return f; - if (_tcslen (name) <= 2) - return NULL; - if (name[1] != ':') { - _tcscpy (tmp, start_path_data); - _tcscat (tmp, name); - f = zfile_fopen_x (tmp, mode, mask, index); - if (f) - return f; - } -#if 0 - name += 2; - if (name[0] == '/' || name[0] == '\\') - name++; - for (;;) { - _tcscpy (tmp, start_path_data); - _tcscpy (tmp, name); - f = zfile_fopen_x (tmp, mode, mask); - if (f) - return f; - while (name[0]) { - name++; - if (name[-1] == '/' || name[-1] == '\\') - break; - } - if (name[0] == 0) - break; - } -#endif - return NULL; -} - -static struct zfile *zfile_fopenx (const TCHAR *name, const TCHAR *mode, int mask, int index) -{ - struct zfile *zf; - //write_log (_T("zfile_fopen('%s','%s',%08x,%d)\n"), name, mode, mask, index); - zf = zfile_fopenx2 (name, mode, mask, index); - //write_log (_T("=%p\n"), zf); - return zf; -} - -struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode, int mask) -{ - return zfile_fopenx (name, mode, mask, 0); -} -struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode) -{ - return zfile_fopenx (name, mode, 0, 0); -} -struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode, int mask, int index) -{ - return zfile_fopenx (name, mode, mask, index); -} - -struct zfile *zfile_dup (struct zfile *zf) -{ - struct zfile *nzf; - if (!zf) - return NULL; - if (zf->archiveparent) - checkarchiveparent (zf); - if (zf->userdata) - return NULL; - if (!zf->data && zf->dataseek) { - nzf = zfile_create (zf); - } else if (zf->data) { - nzf = zfile_create (zf); - nzf->data = xmalloc (uae_u8, zf->size); - memcpy (nzf->data, zf->data, zf->size); - nzf->size = zf->size; - nzf->datasize = zf->datasize; - } else { - if (zf->zipname) { - nzf = openzip (zf->name); - if (nzf) - return nzf; - } - FILE *ff = _tfopen (zf->name, zf->mode); - if (!ff) - return NULL; - nzf = zfile_create (zf); - nzf->f = ff; - } - zfile_fseek (nzf, zf->seek, SEEK_SET); - if (zf->name) - nzf->name = my_strdup (zf->name); - if (nzf->zipname) - nzf->zipname = my_strdup (zf->zipname); - nzf->zfdmask = zf->zfdmask; - nzf->mode = my_strdup (zf->mode); - nzf->size = zf->size; - return nzf; -} - -int zfile_exists (const TCHAR *name) -{ - struct zfile *z; - - if (my_existsfile (name)) - return 1; - z = zfile_fopen (name, _T("rb"), ZFD_NORMAL | ZFD_CHECKONLY); - if (!z) - return 0; - zfile_fclose (z); - return 1; -} - -int zfile_iscompressed (struct zfile *z) -{ - return z->data ? 1 : 0; -} - -struct zfile *zfile_fopen_empty (struct zfile *prev, const TCHAR *name, uae_u64 size) -{ - struct zfile *l; - l = zfile_create (prev); - l->name = my_strdup (name ? name : _T("")); - if (size) { - l->data = xcalloc (uae_u8, size); - if (!l->data) { - xfree (l); - return NULL; - } - l->size = size; - l->datasize = size; - l->allocsize = size; - } else { - l->data = xcalloc (uae_u8, 1000); - l->size = 0; - l->allocsize = 1000; - } - return l; -} - -struct zfile *zfile_fopen_empty (struct zfile *prev, const TCHAR *name) -{ - return zfile_fopen_empty (prev, name, 0); -} - -struct zfile *zfile_fopen_parent (struct zfile *z, const TCHAR *name, uae_u64 offset, uae_u64 size) -{ - struct zfile *l; - - if (z == NULL) - return NULL; - l = zfile_create (z); - if (name) - l->name = my_strdup (name); - else if (z->name) - l->name = my_strdup (z->name); - l->size = size; - l->datasize = size; - l->offset = offset; - for (;;) { - l->parent = z; - l->useparent = 1; - if (!z->parent) - break; - l->offset += z->offset; - z = z->parent; - } - z->opencnt++; - return l; -} - -struct zfile *zfile_fopen_load_zfile (struct zfile *f) -{ - struct zfile *l = zfile_fopen_empty (f, f->name, f->size); - if (!l) - return NULL; - zfile_fseek (f, 0, SEEK_SET); - zfile_fread (l->data, f->size, 1, f); - return l; -} - -struct zfile *zfile_fopen_data (const TCHAR *name, uae_u64 size, const uae_u8 *data) -{ - struct zfile *l; - l = zfile_create (NULL); - l->name = my_strdup (name ? name : _T("")); - l->data = xmalloc (uae_u8, size); - l->size = size; - l->datasize = size; - memcpy (l->data, data, size); - return l; -} - -uae_u8 *zfile_load_data (const TCHAR *name, const uae_u8 *data,int datalen, int *outlen) -{ - struct zfile *zf, *f; - int size; - uae_u8 *out; - - zf = zfile_fopen_data (name, datalen, data); - f = zfile_gunzip (zf); - size = f->datasize; - zfile_fseek (f, 0, SEEK_SET); - out = xmalloc (uae_u8, size); - zfile_fread (out, 1, size, f); - zfile_fclose (f); - *outlen = size; - return out; -} - -int zfile_truncate (struct zfile *z, uae_s64 size) -{ - if (z->data) { - if (z->size > size) { - z->size = size; - if (z->datasize > z->size) - z->datasize = z->size; - if (z->seek > z->size) - z->seek = z->size; - return 1; - } - return 0; - } else { - /* !!! */ - return 0; - } -} - -uae_s64 zfile_size (struct zfile *z) -{ - return z->size; -} - -uae_s64 zfile_ftell (struct zfile *z) -{ - if (z->data || z->dataseek || z->parent) - return z->seek; - return _ftelli64 (z->f); -} - -uae_s64 zfile_fseek (struct zfile *z, uae_s64 offset, int mode) -{ - if (z->zfileseek) - return z->zfileseek (z, offset, mode); - if (z->data || z->dataseek || (z->parent && z->useparent)) { - int ret = 0; - switch (mode) - { - case SEEK_SET: - z->seek = offset; - break; - case SEEK_CUR: - z->seek += offset; - break; - case SEEK_END: - z->seek = z->size + offset; - break; - } - if (z->seek < 0) { - z->seek = 0; - ret = 1; - } - if (z->seek > z->size) { - z->seek = z->size; - ret = 1; - } - return ret; - } else { - return _fseeki64 (z->f, offset, mode); - } - return 1; -} - -size_t zfile_fread (void *b, size_t l1, size_t l2, struct zfile *z) -{ - if (z->zfileread) - return z->zfileread (b, l1, l2, z); - if (z->data) { - if (z->datasize < z->size && z->seek + l1 * l2 > z->datasize) { - if (z->archiveparent) { - archive_unpackzfile (z); - return zfile_fread (b, l1, l2, z); - } - return 0; - } - if (z->seek + l1 * l2 > z->size) { - if (l1) - l2 = (z->size - z->seek) / l1; - else - l2 = 0; - if (l2 < 0) - l2 = 0; - } - memcpy (b, z->data + z->offset + z->seek, l1 * l2); - z->seek += l1 * l2; - return l2; - } - if (z->parent && z->useparent) { - size_t ret; - uae_s64 v; - uae_s64 size = z->size; - v = z->seek; - if (v + l1 * l2 > size) { - if (l1) - l2 = (size - v) / l1; - else - l2 = 0; - if (l2 < 0) - l2 = 0; - } - zfile_fseek (z->parent, z->seek + z->offset, SEEK_SET); - v = z->seek; - ret = zfile_fread (b, l1, l2, z->parent); - z->seek = v + l1 * ret; - return ret; - } - return fread (b, l1, l2, z->f); -} - -size_t zfile_fwrite (const void *b, size_t l1, size_t l2, struct zfile *z) -{ - if (z->archiveparent) - return 0; - if (z->zfilewrite) - return z->zfilewrite (b, l1, l2, z); - if (z->parent && z->useparent) - return 0; - if (z->data) { - uae_s64 off = z->seek + l1 * l2; - if (z->allocsize == 0) { - write_log (_T("zfile_fwrite(data,%s) but allocsize=0!\n"), z->name); - return 0; - } - if (off > z->allocsize) { - if (z->allocsize < off) - z->allocsize = off; - z->allocsize += z->size / 2; - if (z->allocsize < 10000) - z->allocsize = 10000; - z->data = xrealloc (uae_u8, z->data, z->allocsize); - z->datasize = z->size = off; - } - memcpy (z->data + z->seek, b, l1 * l2); - z->seek += l1 * l2; - if (z->seek > z->size) - z->size = z->seek; - if (z->size > z->datasize) - z->datasize = z->size; - return l2; - } - return fwrite (b, l1, l2, z->f); -} - -size_t zfile_fputs (struct zfile *z, const TCHAR *s) -{ - char *s2 = ua (s); - size_t t; - t = zfile_fwrite (s2, strlen (s2), 1, z); - xfree (s2); - return t; -} - -char *zfile_fgetsa(char *s, int size, struct zfile *z) -{ - checkarchiveparent (z); - if (z->data) { - char *os = s; - int i; - for (i = 0; i < size - 1; i++) { - if (z->seek == z->size) { - if (i == 0) - return NULL; - break; - } - *s = z->data[z->seek++]; - if (*s == '\n') { - s++; - break; - } - s++; - } - *s = 0; - return os; - } else { - return fgets(s, size, z->f); - } -} - -TCHAR *zfile_fgets (TCHAR *s, int size, struct zfile *z) -{ - checkarchiveparent (z); - if (z->data) { - char s2[MAX_DPATH]; - char *p = s2; - int i; - for (i = 0; i < size - 1; i++) { - if (z->seek == z->size) { - if (i == 0) - return NULL; - break; - } - *p = z->data[z->seek++]; - if (*p == 0 && i == 0) - return NULL; - if (*p == '\n' || *p == 0) { - p++; - break; - } - p++; - } - *p = 0; - if (size > strlen (s2) + 1) - size = strlen (s2) + 1; - au_copy (s, size, s2); - return s + size; - } else { - char s2[MAX_DPATH]; - char *s1; - s1 = fgets (s2, size, z->f); - if (!s1) - return NULL; - if (size > strlen (s2) + 1) - size = strlen (s2) + 1; - au_copy (s, size, s2); - return s + size; - } -} - -int zfile_putc (int c, struct zfile *z) -{ - uae_u8 b = (uae_u8)c; - return zfile_fwrite (&b, 1, 1, z) ? 1 : -1; -} - -int zfile_getc (struct zfile *z) -{ - checkarchiveparent (z); - int out = -1; - if (z->data) { - if (z->seek < z->size) { - out = z->data[z->seek++]; - } - } else { - out = fgetc (z->f); - } - return out; -} - -int zfile_ferror (struct zfile *z) -{ - return 0; -} - -uae_u8 *zfile_getdata (struct zfile *z, uae_s64 offset, int len) -{ - uae_s64 pos = zfile_ftell (z); - uae_u8 *b; - if (len < 0) { - zfile_fseek (z, 0, SEEK_END); - len = zfile_ftell (z); - zfile_fseek (z, 0, SEEK_SET); - } - b = xmalloc (uae_u8, len); - zfile_fseek (z, offset, SEEK_SET); - zfile_fread (b, len, 1, z); - zfile_fseek (z, pos, SEEK_SET); - return b; -} - -int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize) -{ - z_stream zs; - int v; - uae_u8 inbuf[4096]; - int incnt; - - memset (&zs, 0, sizeof(zs)); - if (inflateInit_ (&zs, ZLIB_VERSION, sizeof(z_stream)) != Z_OK) - return 0; - zs.next_out = (Bytef*)dst; - zs.avail_out = dstsize; - incnt = 0; - v = Z_OK; - while (v == Z_OK && zs.avail_out > 0) { - if (zs.avail_in == 0) { - int left = srcsize - incnt; - if (left == 0) - break; - if (left > sizeof (inbuf)) - left = sizeof (inbuf); - zs.next_in = inbuf; - zs.avail_in = zfile_fread (inbuf, 1, left, src); - incnt += left; - } - v = inflate (&zs, 0); - } - inflateEnd (&zs); - return 0; -} - -int zfile_zcompress (struct zfile *f, void *src, int size) -{ - int v; - z_stream zs; - uae_u8 outbuf[4096]; - - memset (&zs, 0, sizeof (zs)); - if (deflateInit_ (&zs, Z_DEFAULT_COMPRESSION, ZLIB_VERSION, sizeof(z_stream)) != Z_OK) - return 0; - zs.next_in = (Bytef*)src; - zs.avail_in = size; - v = Z_OK; - while (v == Z_OK) { - zs.next_out = outbuf; - zs.avail_out = sizeof (outbuf); - v = deflate(&zs, Z_NO_FLUSH | Z_FINISH); - if (sizeof(outbuf) - zs.avail_out > 0) - zfile_fwrite (outbuf, 1, sizeof (outbuf) - zs.avail_out, f); - } - deflateEnd(&zs); - return zs.total_out; -} - -TCHAR *zfile_getname (struct zfile *f) -{ - return f ? f->name : NULL; -} - -TCHAR *zfile_getfilename (struct zfile *f) -{ - int i; - if (f->name == NULL) - return NULL; - for (i = _tcslen (f->name) - 1; i >= 0; i--) { - if (f->name[i] == '\\' || f->name[i] == '/' || f->name[i] == ':') { - i++; - return &f->name[i]; - } - } - return f->name; -} - -uae_u32 zfile_crc32 (struct zfile *f) -{ - uae_u8 *p; - int pos, size; - uae_u32 crc; - - if (!f) - return 0; - if (f->data) - return get_crc32 (f->data, f->size); - pos = zfile_ftell (f); - zfile_fseek (f, 0, SEEK_END); - size = zfile_ftell (f); - p = xmalloc (uae_u8, size); - if (!p) - return 0; - memset (p, 0, size); - zfile_fseek (f, 0, SEEK_SET); - zfile_fread (p, 1, size, f); - zfile_fseek (f, pos, SEEK_SET); - crc = get_crc32 (p, size); - xfree (p); - return crc; -} - -static struct zvolume *zvolume_list; - -static void recurparent (TCHAR *newpath, struct znode *zn, int recurse) -{ - if (zn->parent && (&zn->volume->root != zn->parent || zn->volume->parentz == NULL)) { - if (&zn->volume->root == zn->parent && zn->volume->parentz == NULL && !_tcscmp (zn->name, zn->parent->name)) - goto end; - recurparent (newpath, zn->parent, recurse); - } else { - struct zvolume *zv = zn->volume; - if (zv->parentz && recurse) - recurparent (newpath, zv->parentz, recurse); - } -end: - if (newpath[0]) - _tcscat (newpath, FSDB_DIR_SEPARATOR_S); - _tcscat (newpath, zn->name); -} - -static struct znode *znode_alloc(struct znode *parent, const TCHAR *name) -{ - TCHAR fullpath[MAX_DPATH]; - TCHAR tmpname[MAX_DPATH]; - struct znode *zn = xcalloc (struct znode, 1); - struct znode *zn2; - - _tcscpy (tmpname, name); - zn2 = parent->child; - while (zn2) { - if (!_tcscmp (zn2->name, tmpname)) { - TCHAR *ext = _tcsrchr (tmpname, '.'); - if (ext && ext > tmpname + 2 && ext[-2] == '.') { - ext[-1]++; - } else if (ext) { - memmove (ext + 2, ext, (_tcslen (ext) + 1) * sizeof (TCHAR)); - ext[0] = '.'; - ext[1] = '1'; - } else { - int len = _tcslen (tmpname); - tmpname[len] = '.'; - tmpname[len + 1] = '1'; - tmpname[len + 2] = 0; - } - zn2 = parent->child; - continue; - } - zn2 = zn2->sibling; - } - - fullpath[0] = 0; - recurparent (fullpath, parent, FALSE); - _tcscat (fullpath, FSDB_DIR_SEPARATOR_S); - _tcscat (fullpath, tmpname); -#ifdef ZFILE_DEBUG - write_log (_T("znode_alloc vol='%s' parent='%s' name='%s'\n"), parent->volume->root.name, parent->name, name); -#endif - zn->fullname = my_strdup(fullpath); - zn->name = my_strdup(tmpname); - zn->volume = parent->volume; - zn->volume->last->next = zn; - zn->prev = zn->volume->last; - zn->volume->last = zn; - return zn; -} - -static struct znode *znode_alloc_child(struct znode *parent, const TCHAR *name) -{ - struct znode *zn = znode_alloc(parent, name); - - if (!parent->child) { - parent->child = zn; - } else { - struct znode *pn = parent->child; - while (pn->sibling) - pn = pn->sibling; - pn->sibling = zn; - } - zn->parent = parent; - return zn; -} -static struct znode *znode_alloc_sibling(struct znode *sibling, const TCHAR *name) -{ - struct znode *zn = znode_alloc(sibling->parent, name); - - if (!sibling->sibling) { - sibling->sibling = zn; - } else { - struct znode *pn = sibling->sibling; - while (pn->sibling) - pn = pn->sibling; - pn->sibling = zn; - } - zn->parent = sibling->parent; - return zn; -} - -static void zvolume_addtolist(struct zvolume *zv) -{ - if (!zv) - return; - if (!zvolume_list) { - zvolume_list = zv; - } else { - struct zvolume *v = zvolume_list; - while (v->next) - v = v->next; - v->next = zv; - } -} - -static struct zvolume *zvolume_alloc_2 (const TCHAR *name, struct zfile *z, unsigned int id, void *handle, const TCHAR *volname) -{ - struct zvolume *zv = xcalloc (struct zvolume, 1); - struct znode *root; - uae_s64 pos; - int i; - - root = &zv->root; - zv->last = root; - zv->archive = z; - zv->handle = handle; - zv->id = id; - zv->blocks = 4; - if (z) - zv->zfdmask = z->zfdmask; - root->volume = zv; - root->type = ZNODE_DIR; - i = 0; - if (name[0] != '/' && name[0] != '\\' && _tcsncmp (name, _T(".\\"), 2) != 0 && _tcsncmp(name, _T("..\\"), 3) != 0) { - if (_tcschr (name, ':') == 0) { - for (i = _tcslen (name) - 1; i > 0; i--) { - if (name[i] == FSDB_DIR_SEPARATOR) { - i++; - break; - } - } - } - } - root->name = my_strdup (name + i); - root->fullname = my_strdup(name); -#ifdef ZFILE_DEBUG - write_log (_T("created zvolume: '%s' (%s)\n"), root->name, root->fullname); -#endif - if (volname) - zv->volumename = my_strdup (volname); - if (z) { - pos = zfile_ftell(z); - zfile_fseek(z, 0, SEEK_END); - zv->archivesize = zfile_ftell(z); - zfile_fseek(z, pos, SEEK_SET); - } - return zv; -} -struct zvolume *zvolume_alloc (struct zfile *z, unsigned int id, void *handle, const TCHAR *volumename) -{ - return zvolume_alloc_2 (zfile_getname (z), z, id, handle, volumename); -} -struct zvolume *zvolume_alloc_nofile (const TCHAR *name, unsigned int id, void *handle, const TCHAR *volumename) -{ - return zvolume_alloc_2 (name, NULL, id, handle, volumename); -} -struct zvolume *zvolume_alloc_empty (struct zvolume *prev, const TCHAR *name) -{ - struct zvolume *zv = zvolume_alloc_2(name, 0, 0, 0, NULL); - if (!zv) - return NULL; - if (prev) - zv->zfdmask = prev->zfdmask; - return zv; -} - -static struct zvolume *get_zvolume(const TCHAR *path) -{ - struct zvolume *zv = zvolume_list; - while (zv) { - TCHAR *s = zfile_getname (zv->archive); - if (!s) - s = zv->root.name; - if (_tcslen (path) >= _tcslen (s) && !memcmp (path, s, _tcslen (s) * sizeof (TCHAR))) - return zv; - zv = zv->next; - } - return NULL; -} - -static struct zvolume *zfile_fopen_archive_ext (struct znode *parent, struct zfile *zf, int flags) -{ - struct zvolume *zv = NULL; - TCHAR *name = zfile_getname (zf); - TCHAR *ext; - uae_u8 header[7]; - - if (!name) - return NULL; - - memset (header, 0, sizeof (header)); - zfile_fseek (zf, 0, SEEK_SET); - zfile_fread (header, sizeof (header), 1, zf); - zfile_fseek (zf, 0, SEEK_SET); - - ext = _tcsrchr (name, '.'); - if (ext != NULL) { - ext++; - if (flags & ZFD_ARCHIVE) { -#ifdef A_LHA - if (strcasecmp (ext, _T("lha")) == 0 || strcasecmp (ext, _T("lzh")) == 0) - zv = archive_directory_lha (zf); -#endif -#ifdef A_ZIP - if (strcasecmp (ext, _T("zip")) == 0) - zv = archive_directory_zip (zf); -#endif -#ifdef A_7Z - if (strcasecmp (ext, _T("7z")) == 0) - zv = archive_directory_7z (zf); -#endif -#ifdef A_LZX - if (strcasecmp (ext, _T("lzx")) == 0) - zv = archive_directory_lzx (zf); -#endif -#ifdef A_RAR - if (strcasecmp (ext, _T("rar")) == 0) - zv = archive_directory_rar (zf); -#endif - if (strcasecmp (ext, _T("tar")) == 0) - zv = archive_directory_tar (zf); - } - if (flags & ZFD_ADF) { - if (strcasecmp (ext, _T("adf")) == 0 && !memcmp (header, "DOS", 3)) - zv = archive_directory_adf (parent, zf); - } - if (flags & ZFD_HD) { - if (strcasecmp (ext, _T("hdf")) == 0) { - if (!memcmp (header, "RDSK", 4)) - zv = archive_directory_rdb (zf); - else - zv = archive_directory_adf (parent, zf); - } - } - } - return zv; -} - - -static struct zvolume *zfile_fopen_archive_data (struct znode *parent, struct zfile *zf, int flags) -{ - struct zvolume *zv = NULL; - uae_u8 header[32]; - - memset (header, 0, sizeof (header)); - zfile_fread (header, sizeof (header), 1, zf); - zfile_fseek (zf, 0, SEEK_SET); - if (flags & ZFD_ARCHIVE) { -#ifdef A_ZIP - if (header[0] == 'P' && header[1] == 'K') - zv = archive_directory_zip (zf); -#endif -#ifdef A_RAR - if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!') - zv = archive_directory_rar (zf); -#endif -#ifdef A_LZX - if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X') - zv = archive_directory_lzx (zf); -#endif -#ifdef A_LHA - if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-') - zv = archive_directory_lha (zf); -#endif - } - if (flags & ZFD_ADF) { - if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) - zv = archive_directory_adf (parent, zf); - } - if (flags & ZFD_HD) { - if (header[0] == 'R' && header[1] == 'D' && header[2] == 'S' && header[3] == 'K') - zv = archive_directory_rdb (zf); - if (isfat (header)) - zv = archive_directory_fat (zf); - } - return zv; -} - -static struct znode *get_znode (struct zvolume *zv, const TCHAR *ppath, int); - -static void zfile_fopen_archive_recurse2 (struct zvolume *zv, struct znode *zn, int flags) -{ - struct zvolume *zvnew; - struct znode *zndir; - TCHAR tmp[MAX_DPATH]; - - _stprintf (tmp, _T("%s.DIR"), zn->fullname + _tcslen (zv->root.name) + 1); - zndir = get_znode(zv, tmp, TRUE); - if (!zndir) { - struct zarchive_info zai = { 0 }; - zvnew = zvolume_alloc_empty (zv, tmp); - zvnew->parentz = zn; - zai.name = tmp; - zai.tv.tv_sec = zn->mtime.tv_sec; - zai.tv.tv_usec = zn->mtime.tv_usec; - zai.comment = zv->volumename; - if (zn->flags < 0) - zai.flags = zn->flags; - zndir = zvolume_adddir_abs(zv, &zai); - zndir->type = ZNODE_VDIR; - zndir->vfile = zn; - zndir->vchild = zvnew; - zvnew->parent = zv; - zndir->offset = zn->offset; - zndir->offset2 = zn->offset2; - } -} - -static int zfile_fopen_archive_recurse (struct zvolume *zv, int flags) -{ - struct znode *zn; - int i, added; - - added = 0; - zn = zv->root.child; - while (zn) { - int done = 0; - struct zfile *z; - TCHAR *ext = _tcsrchr (zn->name, '.'); - if (ext && !zn->vchild && zn->type == ZNODE_FILE) { - for (i = 0; !done && archive_extensions[i]; i++) { - if (!strcasecmp (ext + 1, archive_extensions[i])) { - zfile_fopen_archive_recurse2 (zv, zn, flags); - done = 1; - } - } - } - if (!done) { - z = archive_getzfile (zn, zv->method, 0); - if (z && iszip (z)) - zfile_fopen_archive_recurse2 (zv, zn, flags); - } - zn = zn->next; - } - return 0; -} - - -static struct zvolume *prepare_recursive_volume (struct zvolume *zv, const TCHAR *path, int flags) -{ - struct zfile *zf = NULL; - struct zvolume *zvnew = NULL; - int done = 0; - -#ifdef ZFILE_DEBUG - write_log (_T("unpacking '%s'\n"), path); -#endif - zf = zfile_open_archive (path, 0); - if (!zf) - goto end; - zvnew = zfile_fopen_archive_ext (zv->parentz, zf, flags); - if (!zvnew && !(flags & ZFD_NORECURSE)) { -#if 1 - zvnew = archive_directory_plain (zf); - if (zvnew) { - zfile_fopen_archive_recurse (zvnew, flags); - done = 1; - } -#else - int rc; - int index; - struct zfile *zf2, *zf3; - TCHAR oldname[MAX_DPATH]; - _tcscpy (oldname, zf->name); - index = 0; - for (;;) { - zf3 = zfile_dup (zf); - if (!zf3) - break; - zf2 = zuncompress (&zv->root, zf3, 0, ZFD_ALL, &rc, index); - if (zf2) { - zvnew = archive_directory_plain (zf2); - if (zvnew) { - zvnew->parent = zv->parent; - zfile_fopen_archive_recurse (zvnew); - done = 1; - } - } else { - zfile_fclose (zf3); - if (rc <= 0) - break; - } - index++; - break; // TODO - } -#endif - } else if (zvnew) { - zvnew->parent = zv->parent; - zfile_fopen_archive_recurse (zvnew, flags); - done = 1; - } - if (!done) - goto end; - zfile_fclose_archive(zv); - return zvnew; -end: - write_log (_T("unpack '%s' failed\n"), path); - zfile_fclose_archive (zvnew); - zfile_fclose(zf); - return NULL; -} - -static struct znode *get_znode (struct zvolume *zv, const TCHAR *ppath, int recurse) -{ - struct znode *zn; - TCHAR path[MAX_DPATH], zpath[MAX_DPATH]; - - if (!zv) - return NULL; - _tcscpy (path, ppath); - zn = &zv->root; - while (zn) { - zpath[0] = 0; - recurparent (zpath, zn, recurse); - if (zn->type == ZNODE_FILE) { - if (!_tcsicmp (zpath, path)) - return zn; - } else { - int len = _tcslen (zpath); - if (_tcslen (path) >= len && (path[len] == 0 || path[len] == FSDB_DIR_SEPARATOR) && !_tcsnicmp (zpath, path, len)) { - if (path[len] == 0) - return zn; - if (zn->vchild) { - /* jump to separate tree, recursive archives */ - struct zvolume *zvdeep = zn->vchild; - if (zvdeep->archive == NULL) { - TCHAR newpath[MAX_DPATH]; - newpath[0] = 0; - recurparent (newpath, zn, recurse); -#ifdef ZFILE_DEBUG - write_log (_T("'%s'\n"), newpath); -#endif - zvdeep = prepare_recursive_volume (zvdeep, newpath, ZFD_ALL); - if (!zvdeep) { - write_log (_T("failed to unpack '%s'\n"), newpath); - return NULL; - } - /* replace dummy empty volume with real volume */ - zn->vchild = zvdeep; - zvdeep->parentz = zn; - } - zn = zvdeep->root.child; - } else { - zn = zn->child; - } - continue; - } - } - zn = zn->sibling; - } - return NULL; -} - -static void addvolumesize (struct zvolume *zv, uae_s64 size) -{ - unsigned int blocks = (size + 511) / 512; - - if (blocks == 0) - blocks++; - while (zv) { - zv->blocks += blocks; - zv->size += size; - zv = zv->parent; - } -} - -struct znode *znode_adddir(struct znode *parent, const TCHAR *name, struct zarchive_info *zai) -{ - struct znode *zn; - TCHAR path[MAX_DPATH]; - - path[0] = 0; - recurparent (path, parent, FALSE); - _tcscat (path, FSDB_DIR_SEPARATOR_S); - _tcscat (path, name); - zn = get_znode (parent->volume, path, FALSE); - if (zn) - return zn; - zn = znode_alloc_child(parent, name); - zn->mtime.tv_sec = zai->tv.tv_sec; - zn->mtime.tv_usec = zai->tv.tv_usec; - zn->type = ZNODE_DIR; - if (zai->comment) - zn->comment = my_strdup (zai->comment); - if (zai->flags < 0) - zn->flags = zai->flags; - addvolumesize(parent->volume, 0); - return zn; -} - -struct znode *zvolume_adddir_abs(struct zvolume *zv, struct zarchive_info *zai) -{ - struct znode *zn2; - TCHAR *path = my_strdup(zai->name); - TCHAR *p, *p2; - int i; - - if (_tcslen (path) > 0) { - /* remove possible trailing / or \ */ - TCHAR last; - last = path[_tcslen (path) - 1]; - if (last == '/' || last == '\\') - path[_tcslen (path) - 1] = 0; - } - zn2 = &zv->root; - p = p2 = path; - for (i = 0; path[i]; i++) { - if (path[i] == '/' || path[i] == '\\') { - path[i] = 0; - zn2 = znode_adddir(zn2, p, zai); - path[i] = FSDB_DIR_SEPARATOR; - p = p2 = &path[i + 1]; - } - } - return znode_adddir(zn2, p, zai); -} - -struct znode *zvolume_addfile_abs(struct zvolume *zv, struct zarchive_info *zai) -{ - struct znode *zn, *zn2; - int i; - TCHAR *path = my_strdup (zai->name); - TCHAR *p, *p2; - - zn2 = &zv->root; - p = p2 = path; - for (i = 0; path[i]; i++) { - if (path[i] == '/' || path[i] == '\\') { - path[i] = 0; - zn2 = znode_adddir(zn2, p, zai); - path[i] = FSDB_DIR_SEPARATOR; - p = p2 = &path[i + 1]; - } - } - if (p2) { - zn = znode_alloc_child(zn2, p2); - zn->size = zai->size; - zn->type = ZNODE_FILE; - zn->mtime.tv_sec = zai->tv.tv_sec; - zn->mtime.tv_usec = zai->tv.tv_usec; - if (zai->comment) - zn->comment = my_strdup(zai->comment); - zn->flags = zai->flags; - addvolumesize(zn->volume, zai->size); - } - xfree(path); - return zn; -} - -struct zvolume *zfile_fopen_directory (const TCHAR *dirname) -{ - struct zvolume *zv = NULL; - struct my_opendir_s *dir; - TCHAR fname[MAX_DPATH]; - - dir = my_opendir (dirname); - if (!dir) - return NULL; - zv = zvolume_alloc_nofile (dirname, ArchiveFormatDIR, NULL, NULL); - while (my_readdir (dir, fname)) { - TCHAR fullname[MAX_DPATH]; - struct mystat statbuf; - struct zarchive_info zai = { 0 }; - if (!_tcscmp (fname, _T(".")) || !_tcscmp (fname, _T(".."))) - continue; - _tcscpy (fullname, dirname); - _tcscat (fullname, FSDB_DIR_SEPARATOR_S); - _tcscat (fullname, fname); - if (!my_stat (fullname, &statbuf)) - continue; - zai.name = fname; - zai.size = statbuf.size; - zai.tv.tv_sec = statbuf.mtime.tv_sec; - zai.tv.tv_usec = statbuf.mtime.tv_usec; - if (statbuf.mode & FILEFLAG_DIR) { - zvolume_adddir_abs (zv, &zai); - } else { - struct znode *zn; - zn = zvolume_addfile_abs (zv, &zai); - //zfile_fopen_archive_recurse2 (zv, zn); - } - } - my_closedir (dir); - // zfile_fopen_archive_recurse (zv); - if (zv) - zvolume_addtolist (zv); - return zv; -} - -struct zvolume *zfile_fopen_archive (const TCHAR *filename, int flags) -{ - struct zvolume *zv = NULL; - struct zfile *zf = zfile_fopen_nozip (filename, _T("rb")); - - if (!zf) - return NULL; - zf->zfdmask = flags; - zv = zfile_fopen_archive_ext (NULL, zf, flags); - if (!zv) - zv = zfile_fopen_archive_data (NULL, zf, flags); -#if 0 - if (!zv) { - struct zfile *zf2 = zuncompress (zf, 0, 0); - if (zf2 != zf) { - zf = zf2; - zv = zfile_fopen_archive_ext(zf, flags); - if (!zv) - zv = zfile_fopen_archive_data(zf, flags); - } - } -#endif - /* pointless but who cares? */ - if (!zv && !(flags & ZFD_NORECURSE)) - zv = archive_directory_plain (zf); - -#if RECURSIVE_ARCHIVES - if (zv && !(flags & ZFD_NORECURSE)) - zfile_fopen_archive_recurse (zv, flags); -#endif - - if (zv) - zvolume_addtolist (zv); - else - zfile_fclose(zf); - return zv; -} -struct zvolume *zfile_fopen_archive (const TCHAR *filename) -{ - return zfile_fopen_archive (filename, ZFD_ALL); -} - -struct zvolume *zfile_fopen_archive_root (const TCHAR *filename, int flags) -{ - TCHAR path[MAX_DPATH], *p1, *p2, *lastp; - struct zvolume *zv = NULL; - //int last = 0; - int num, i; - - if (my_existsdir (filename)) - return zfile_fopen_directory (filename); - - num = 1; - lastp = NULL; - for (;;) { - _tcscpy (path, filename); - p1 = p2 = path; - for (i = 0; i < num; i++) { - while (*p1 != FSDB_DIR_SEPARATOR && *p1 != 0) - p1++; - if (*p1 == 0 && p1 == lastp) - return NULL; - if (i + 1 < num) - p1++; - } - *p1 = 0; - lastp = p1; - if (my_existsfile (p2)) - return zfile_fopen_archive (p2, flags); - num++; - } - -#if 0 - while (!last) { - while (*p1 != FSDB_DIR_SEPARATOR && *p1 != 0) - p1++; - if (*p1 == 0) - last = 1; - *p1 = 0; - if (!zv) { - zv = zfile_fopen_archive (p2); - if (!zv) - return NULL; - } else { - struct znode *zn = get_znode (zv, p2); - if (!zn) - return NULL; - } - p2 = p1 + 1; - } - return zv; -#endif -} - -void zfile_fclose_archive(struct zvolume *zv) -{ - struct znode *zn; - struct zvolume *v; - - if (!zv) - return; - zn = &zv->root; - while (zn) { - struct znode *zn2 = zn->next; - if (zn->vchild) - zfile_fclose_archive(zn->vchild); - xfree(zn->comment); - xfree(zn->fullname); - xfree(zn->name); - zfile_fclose(zn->f); - memset (zn, 0, sizeof (struct znode)); - if (zn != &zv->root) - xfree(zn); - zn = zn2; - } - archive_access_close (zv->handle, zv->id); - if (zvolume_list == zv) { - zvolume_list = zvolume_list->next; - } else { - v = zvolume_list; - while (v) { - if (v->next == zv) { - v->next = zv->next; - break; - } - v = v->next; - } - } - xfree(zv); -} - -struct zdirectory { - TCHAR *parentpath; - struct znode *first; - struct znode *n; - bool doclose; - struct zvolume *zv; - int cnt; - int offset; - TCHAR **filenames; -}; - -struct zdirectory *zfile_opendir_archive (const TCHAR *path, int flags) -{ - struct zvolume *zv = get_zvolume(path); - bool created = false; - if (zv == NULL) { - zv = zfile_fopen_archive (path, flags); - created = true; - } - struct znode *zn = get_znode(zv, path, TRUE); - struct zdirectory *zd; - - if (!zn || (!zn->child && !zn->vchild)) { - if (created) - zfile_fclose_archive (zv); - return NULL; - } - zd = xcalloc (struct zdirectory, 1); - if (created) - zd->zv = zv; - if (zn->child) { - zd->n = zn->child; - } else { - if (zn->vchild->archive == NULL) { - struct zvolume *zvnew = prepare_recursive_volume (zn->vchild, path, flags); - if (zvnew) { - zn->vchild = zvnew; - zvnew->parentz = zn; - } - } - zd->n = zn->vchild->root.next; - } - zd->parentpath = my_strdup (path); - zd->first = zd->n; - return zd; -} -struct zdirectory *zfile_opendir_archive (const TCHAR *path) -{ - return zfile_opendir_archive (path, ZFD_ALL | ZFD_NORECURSE); -} -void zfile_closedir_archive(struct zdirectory *zd) -{ - if (!zd) - return; - zfile_fclose_archive (zd->zv); - xfree (zd->parentpath); - xfree (zd->filenames); - xfree(zd); -} -int zfile_readdir_archive (struct zdirectory *zd, TCHAR *out, bool fullpath) -{ - if (out) - out[0] = 0; - if (!zd->n || (zd->filenames != NULL && zd->offset >= zd->cnt)) - return 0; - if (zd->filenames == NULL) { - struct znode *n = zd->first; - int cnt = 0, len = 0; - while (n) { - cnt++; - n = n->sibling; - } - n = zd->first; - uae_u8 *buf = xmalloc (uae_u8, cnt * sizeof (TCHAR*)); - zd->filenames = (TCHAR**)buf; - buf += cnt * sizeof (TCHAR*); - for (int i = 0; i < cnt; i++) { - zd->filenames[i] = n->name; - n = n->sibling; - } - for (int i = 0; i < cnt; i++) { - for (int j = i + 1; j < cnt; j++) { - if (_tcscmp (zd->filenames[i], zd->filenames[j]) > 0) { - TCHAR *tmp = zd->filenames[i]; - zd->filenames[i] = zd->filenames[j]; - zd->filenames[j] = tmp; - } - } - } - zd->cnt = cnt; - } - if (out == NULL) - return zd->cnt; - if (fullpath) { - _tcscpy (out, zd->parentpath); - _tcscat (out, FSDB_DIR_SEPARATOR_S); - } - _tcscat (out, zd->filenames[zd->offset]); - zd->offset++; - return 1; -} -int zfile_readdir_archive (struct zdirectory *zd, TCHAR *out) -{ - return zfile_readdir_archive (zd, out, false); -} - -struct zfile *zfile_readdir_archive_open (struct zdirectory *zd, const TCHAR *mode) -{ - TCHAR path[MAX_DPATH]; - if (!zfile_readdir_archive (zd, path, true)) - return NULL; - return zfile_fopen (path, mode, ZFD_ARCHIVE | ZFD_NORECURSE); -} - - -void zfile_resetdir_archive (struct zdirectory *zd) -{ - zd->offset = 0; - zd->n = zd->first; -} - -int zfile_fill_file_attrs_archive(const TCHAR *path, int *isdir, int *flags, TCHAR **comment) -{ - struct zvolume *zv = get_zvolume(path); - struct znode *zn = get_znode (zv, path, TRUE); - - *isdir = 0; - *flags = 0; - if (comment) - *comment = 0; - if (!zn) - return 0; - if (zn->type == ZNODE_DIR) - *isdir = 1; - else if (zn->type == ZNODE_VDIR) - *isdir = -1; - *flags = zn->flags; - if (zn->comment && comment) - *comment = my_strdup(zn->comment); - return 1; -} - -int zfile_fs_usage_archive(const TCHAR *path, const TCHAR *disk, struct fs_usage *fsp) -{ - struct zvolume *zv = get_zvolume(path); - - if (!zv) - return -1; - fsp->fsu_blocks = zv->blocks; - fsp->fsu_bavail = 0; - return 0; -} - -int zfile_stat_archive (const TCHAR *path, struct mystat *s) -{ - struct zvolume *zv = get_zvolume(path); - struct znode *zn = get_znode (zv, path, TRUE); - - memset (s, 0, sizeof (struct mystat)); - if (!zn) - return 0; - s->size = zn->size; - s->mtime.tv_sec = zn->mtime.tv_sec; - s->mtime.tv_usec = zn->mtime.tv_usec; - return 1; -} - -uae_s64 zfile_lseek_archive (struct zfile *d, uae_s64 offset, int whence) -{ - uae_s64 old = zfile_ftell (d); - if (old < 0 || zfile_fseek (d, offset, whence)) - return -1; - return old; -} -uae_s64 zfile_fsize_archive (struct zfile *d) -{ - return zfile_size (d); -} - -unsigned int zfile_read_archive (struct zfile *d, void *b, unsigned int size) -{ - return zfile_fread (b, 1, size, d); -} - -void zfile_close_archive (struct zfile *d) -{ - /* do nothing, keep file cached */ -} - -struct zfile *zfile_open_archive (const TCHAR *path, int flags) -{ - struct zvolume *zv = get_zvolume(path); - struct znode *zn = get_znode (zv, path, TRUE); - struct zfile *z; - - if (!zn) - return 0; - if (zn->f) { - zfile_fseek(zn->f, 0, SEEK_SET); - return zn->f; - } - if (zn->vfile) - zn = zn->vfile; - z = archive_getzfile (zn, zn->volume->id, 0); - if (z) - zfile_fseek(z, 0, SEEK_SET); - zn->f = z; - return zn->f; -} - -int zfile_exists_archive (const TCHAR *path, const TCHAR *rel) -{ - TCHAR tmp[MAX_DPATH]; - struct zvolume *zv; - struct znode *zn; - - _stprintf (tmp, _T("%s%c%s"), path, FSDB_DIR_SEPARATOR, rel); - zv = get_zvolume(tmp); - zn = get_znode (zv, tmp, TRUE); - return zn ? 1 : 0; -} - -int zfile_convertimage (const TCHAR *src, const TCHAR *dst) -{ - struct zfile *s, *d; - int ret = 0; - - s = zfile_fopen (src, _T("rb"), ZFD_NORMAL); - if (s) { - uae_u8 *b; - int size; - zfile_fseek (s, 0, SEEK_END); - size = zfile_ftell (s); - zfile_fseek (s, 0, SEEK_SET); - b = xcalloc (uae_u8, size); - if (b) { - if (zfile_fread (b, size, 1, s) == 1) { - d = zfile_fopen (dst, _T("wb"), 0); - if (d) { - if (zfile_fwrite (b, size, 1, d) == 1) - ret = 1; - zfile_fclose (d); - } - } - xfree (b); - } - zfile_fclose (s); - } - return ret; -} - -#ifdef _CONSOLE -static TCHAR *zerror; -#define WRITE_LOG_BUF_SIZE 4096 -void zfile_seterror (const TCHAR *format, ...) -{ - int count; - if (!zerror) { - TCHAR buffer[WRITE_LOG_BUF_SIZE]; - va_list parms; - va_start (parms, format); - count = _vsntprintf (buffer, WRITE_LOG_BUF_SIZE - 1, format, parms); - zerror = my_strdup (buffer); - va_end (parms); - } -} -TCHAR *zfile_geterror (void) -{ - return zerror; -} -#else -void zfile_seterror (const TCHAR *format, ...) -{ -} -#endif + /* + * UAE - The Un*x Amiga Emulator + * + * routines to handle compressed file automatically + * + * (c) 1996 Samuel Devulder, Tim Gunn + * 2002-2007 Toni Wilen + */ + +#define RECURSIVE_ARCHIVES 1 +//#define ZFILE_DEBUG + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "uae.h" +#include "options.h" +#include "zfile.h" +#include "disk.h" +#include "gui.h" +#include "crc32.h" +#include "fsdb.h" +#include "fsusage.h" +#include "zarchive.h" +#include "diskutil.h" + +#include "archivers/zip/unzip.h" +#include "archivers/dms/pfile.h" +#include "archivers/wrp/warp.h" + +static struct zfile *zlist = 0; + +const TCHAR *uae_archive_extensions[] = { _T("zip"), _T("rar"), _T("7z"), _T("lha"), _T("lzh"), _T("lzx"), _T("tar"), NULL }; + +#define MAX_CACHE_ENTRIES 10 + +struct zdisktrack +{ + void *data; + int len; +}; +struct zdiskimage +{ + int tracks; + struct zdisktrack zdisktracks[2 * 84]; +}; +struct zcache +{ + TCHAR *name; + struct zdiskimage *zd; + void *data; + int size; + struct zcache *next; + time_t tm; +}; +static struct zcache *zcachedata; + +static struct zcache *cache_get (const TCHAR *name) +{ + struct zcache *zc = zcachedata; + while (zc) { + if (!_tcscmp (name, zc->name)) { + zc->tm = time (NULL); + return zc; + } + zc = zc->next; + } + return NULL; +} + +static void zcache_flush (void) +{ +} + +static void zcache_free_data (struct zcache *zc) +{ + int i; + if (zc->zd) { + for (i = 0; i < zc->zd->tracks; i++) { + xfree (zc->zd->zdisktracks[i].data); + } + xfree (zc->zd); + } + xfree (zc->data); + xfree (zc->name); +} + +static void zcache_free (struct zcache *zc) +{ + struct zcache *pl = NULL; + struct zcache *l = zcachedata; + struct zcache *nxt; + + while (l != zc) { + if (l == 0) + return; + pl = l; + l = l->next; + } + if (l) + nxt = l->next; + zcache_free_data (zc); + if (l == 0) + return; + if(!pl) + zcachedata = nxt; + else + pl->next = nxt; +} + +static void zcache_close (void) +{ + struct zcache *zc = zcachedata; + while (zc) { + struct zcache *n = zc->next; + zcache_free_data (zc); + xfree (n); + zc = n; + } +} + +static void zcache_check (void) +{ + int cnt = 0; + struct zcache *zc = zcachedata, *last = NULL; + while (zc) { + last = zc; + zc = zc->next; + cnt++; + } + write_log (_T("CACHE: %d\n"), cnt); + if (cnt >= MAX_CACHE_ENTRIES && last) + zcache_free (last); +} + +static struct zcache *zcache_put (const TCHAR *name, struct zdiskimage *data) +{ + struct zcache *zc; + + zcache_check (); + zc = xcalloc (struct zcache, 1); + zc->next = zcachedata; + zcachedata = zc; + zc->zd = data; + zc->name = my_strdup (name); + zc->tm = time (NULL); + return zc; +} + +static void checkarchiveparent (struct zfile *z) +{ + // unpack completely if opened in PEEK mode + if (z->archiveparent) + archive_unpackzfile (z); +} + +static struct zfile *zfile_create (struct zfile *prev) +{ + struct zfile *z; + + z = xmalloc (struct zfile, 1); + if (!z) + return 0; + memset (z, 0, sizeof *z); + z->next = zlist; + zlist = z; + z->opencnt = 1; + if (prev) { + z->zfdmask = prev->zfdmask; + } + return z; +} + +static void zfile_free (struct zfile *f) +{ + if (f->f) + fclose (f->f); + if (f->deleteafterclose) { + _wunlink (f->name); + write_log (_T("deleted temporary file '%s'\n"), f->name); + } + xfree (f->name); + xfree (f->data); + xfree (f->mode); + xfree (f->userdata); + xfree (f); +} + +void zfile_exit (void) +{ + struct zfile *l; + + while ((l = zlist)) { + zlist = l->next; + zfile_free (l); + } +} + +void zfile_fclose (struct zfile *f) +{ + //write_log (_T("%p\n"), f); + if (!f) + return; + if (f->opencnt < 0) { + write_log (_T("zfile: tried to free already closed filehandle!\n")); + return; + } + f->opencnt--; + if (f->opencnt > 0) + return; + f->opencnt = -100; + if (f->parent) { + f->parent->opencnt--; + if (f->parent->opencnt <= 0) + zfile_fclose (f->parent); + } + if (f->archiveparent) { + zfile_fclose (f->archiveparent); + f->archiveparent = NULL; + } + struct zfile *pl = NULL; + struct zfile *nxt; + struct zfile *l = zlist; + while (l!=f) { + if (l == 0) { + write_log (_T("zfile: tried to free already freed or nonexisting filehandle!\n")); + return; + } + pl = l; + l = l->next; + } + if (l) + nxt = l->next; + zfile_free (f); + if (l == 0) + return; + if(!pl) + zlist = nxt; + else + pl->next = nxt; +} + +static void removeext (TCHAR *s, const char *ext) +{ + if (_tcslen (s) < _tcslen (ext)) + return; + if (_tcsicmp (s + _tcslen (s) - _tcslen (ext), ext) == 0) + s[_tcslen (s) - _tcslen (ext)] = 0; +} + +static bool checkwrite (struct zfile *zf, int *retcode) +{ + if (zfile_needwrite (zf)) { + if (retcode) + *retcode = -1; + return true; + } + return false; +} + +static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00}; +static const char *diskimages[] = { _T("adf"), _T("adz"), _T("ipf"), _T("scp"), _T("fdi"), _T("dms"), _T("wrp"), _T("dsq"), 0 }; + +int zfile_gettype (struct zfile *z) +{ + uae_u8 buf[8]; + TCHAR *ext; + + if (!z || !z->name) + return ZFILE_UNKNOWN; + ext = _tcsrchr (z->name, '.'); + if (ext != NULL) { + int i; + ext++; + for (i = 0; diskimages[i]; i++) { + if (strcasecmp (ext, diskimages[i]) == 0) + return ZFILE_DISKIMAGE; + } + if (strcasecmp (ext, _T("roz")) == 0) + return ZFILE_ROM; + if (strcasecmp (ext, _T("uss")) == 0) + return ZFILE_STATEFILE; + if (strcasecmp (ext, _T("rom")) == 0) + return ZFILE_ROM; + if (strcasecmp (ext, _T("key")) == 0) + return ZFILE_KEY; + if (strcasecmp (ext, _T("nvr")) == 0) + return ZFILE_NVR; + if (strcasecmp (ext, _T("uae")) == 0) + return ZFILE_CONFIGURATION; + if (strcasecmp (ext, _T("cue")) == 0 || strcasecmp (ext, _T("iso")) == 0 || strcasecmp (ext, _T("ccd")) == 0 || strcasecmp (ext, _T("mds")) == 0 || strcasecmp (ext, _T("chd")) == 0) + return ZFILE_CDIMAGE; + } + memset (buf, 0, sizeof (buf)); + zfile_fread (buf, 8, 1, z); + zfile_fseek (z, -8, SEEK_CUR); + if (!memcmp (buf, exeheader, sizeof(buf))) + return ZFILE_DISKIMAGE; + if (!memcmp (buf, "UAE--ADF", 8)) + return ZFILE_DISKIMAGE; + if (!memcmp (buf, "UAE-1ADF", 8)) + return ZFILE_DISKIMAGE; + if (!memcmp (buf, "RDSK", 4)) + return ZFILE_HDFRDB; + if (!memcmp (buf, "DOS", 3)) { + if (z->size < 4 * 1024 * 1024) + return ZFILE_DISKIMAGE; + else + return ZFILE_HDF; + } + if (ext != NULL) { + if (strcasecmp (ext, _T("hdf")) == 0) + return ZFILE_HDF; + if (strcasecmp (ext, _T("hdz")) == 0) + return ZFILE_HDF; + } + return ZFILE_UNKNOWN; +} + +#define VHD_DYNAMIC 3 +#define VHD_FIXED 2 + +STATIC_INLINE uae_u32 gl (uae_u8 *p) +{ + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); +} + +static uae_u32 vhd_checksum (uae_u8 *p, int offset) +{ + int i; + uae_u32 sum; + + sum = 0; + for (i = 0; i < 512; i++) { + if (offset >= 0 && i >= offset && i < offset + 4) + continue; + sum += p[i]; + } + return ~sum; +} + +struct zfile_vhd +{ + int vhd_type; + uae_u64 virtsize; + uae_u32 vhd_bamoffset; + uae_u32 vhd_blocksize; + uae_u8 *vhd_header, *vhd_sectormap; + uae_u64 vhd_footerblock; + uae_u32 vhd_bamsize; + uae_u64 vhd_sectormapblock; + uae_u32 vhd_bitmapsize; +}; + + +static uae_u64 vhd_fread2 (struct zfile *zf, void *dataptrv, uae_u64 offset, uae_u64 len) +{ + uae_u32 bamoffset; + uae_u32 sectoroffset; + uae_u64 read; + struct zfile *zp = zf->parent; + struct zfile_vhd *zvhd = (struct zfile_vhd*)zf->userdata; + uae_u8 *dataptr = (uae_u8*)dataptrv; + + //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len); + read = 0; + if (offset & 511) + return read; + if (len & 511) + return read; + while (len > 0) { + bamoffset = (offset / zvhd->vhd_blocksize) * 4 + zvhd->vhd_bamoffset; + sectoroffset = gl (zvhd->vhd_header + bamoffset); + if (sectoroffset == 0xffffffff) { + memset (dataptr, 0, 512); + read += 512; + } else { + int bitmapoffsetbits; + int bitmapoffsetbytes; + int sectormapblock; + + bitmapoffsetbits = (offset / 512) % (zvhd->vhd_blocksize / 512); + bitmapoffsetbytes = bitmapoffsetbits / 8; + sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511); + if (zvhd->vhd_sectormapblock != sectormapblock) { + // read sector bitmap + //write_log (_T("BM %08x\n"), sectormapblock); + zfile_fseek (zp, sectormapblock, SEEK_SET); + if (zfile_fread (zvhd->vhd_sectormap, 1, 512, zp) != 512) + return read; + zvhd->vhd_sectormapblock = sectormapblock; + } + // block allocated in bitmap? + if (zvhd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) { + // read data block + int block = sectoroffset * 512 + zvhd->vhd_bitmapsize + bitmapoffsetbits * 512; + //write_log (_T("DB %08x\n"), block); + zfile_fseek (zp, block, SEEK_SET); + if (zfile_fread (dataptr, 1, 512, zp) != 512) + return read; + } else { + memset (dataptr, 0, 512); + } + read += 512; + } + len -= 512; + dataptr += 512; + offset += 512; + } + return read; +} +static uae_s64 vhd_fread (void *data, uae_u64 l1, uae_u64 l2, struct zfile *zf) +{ + uae_u64 size = l1 * l2; + uae_u64 out = 0; + int len = 0; + + if (!l1 || !l2) + return 0; + if ((zf->seek & 511) || (size & 511)) { + uae_u8 tmp[512]; + + if (zf->seek & 511) { + int s; + s = 512 - (zf->seek & 511); + vhd_fread2 (zf, tmp, zf->seek & ~511, 512); + memcpy ((uae_u8*)data + len, tmp + 512 - s, s); + len += s; + out += s; + zf->seek += s; + } + while (size > 0) { + int s = size > 512 ? 512 : size; + vhd_fread2 (zf, tmp, zf->seek, 512); + memcpy ((uae_u8*)data + len, tmp, s); + zf->seek += s; + size -= s; + out += s; + } + } else { + out = vhd_fread2 (zf, data, zf->seek, size); + zf->seek += out; + out /= l1; + } + return out; +} + +static struct zfile *vhd (struct zfile *z) +{ + uae_u8 tmp[512], tmp2[512]; + uae_u32 v; + struct zfile_vhd *zvhd; + uae_u64 fsize; + + zvhd = xcalloc (struct zfile_vhd, 1); + zfile_fseek (z, 0, SEEK_END); + fsize = zfile_ftell (z); + zfile_fseek (z, 0, SEEK_SET); + if (zfile_fread (tmp, 1, 512, z) != 512) + goto nonvhd; + v = gl (tmp + 8); // features + if ((v & 3) != 2) + goto nonvhd; + v = gl (tmp + 8 + 4); // version + if ((v >> 16) != 1) + goto nonvhd; + zvhd->vhd_type = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4); + if (zvhd->vhd_type != VHD_FIXED && zvhd->vhd_type != VHD_DYNAMIC) + goto nonvhd; + v = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4); + if (v == 0) + goto nonvhd; + if (vhd_checksum (tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v) + goto nonvhd; + zfile_fseek (z, fsize - sizeof tmp2, SEEK_SET); + if (zfile_fread (tmp2, 1, 512, z) != 512) + goto end; + if (memcmp (tmp, tmp2, sizeof tmp)) + goto nonvhd; + zvhd->vhd_footerblock = fsize - 512; + zvhd->virtsize = (uae_u64)(gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8)) << 32; + zvhd->virtsize |= gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8 + 4); + if (zvhd->vhd_type == VHD_DYNAMIC) { + uae_u32 size; + zvhd->vhd_bamoffset = gl (tmp + 8 + 4 + 4 + 4); + if (zvhd->vhd_bamoffset == 0 || zvhd->vhd_bamoffset >= fsize) + goto end; + zfile_fseek (z, zvhd->vhd_bamoffset, SEEK_SET); + if (zfile_fread (tmp, 1, 512, z) != 512) + goto end; + v = gl (tmp + 8 + 8 + 8 + 4 + 4 + 4); + if (vhd_checksum (tmp, 8 + 8 + 8 + 4 + 4 + 4) != v) + goto end; + v = gl (tmp + 8 + 8 + 8); + if ((v >> 16) != 1) + goto end; + zvhd->vhd_blocksize = gl (tmp + 8 + 8 + 8 + 4 + 4); + zvhd->vhd_bamoffset = gl (tmp + 8 + 8 + 4); + zvhd->vhd_bamsize = (((zvhd->virtsize + zvhd->vhd_blocksize - 1) / zvhd->vhd_blocksize) * 4 + 511) & ~511; + size = zvhd->vhd_bamoffset + zvhd->vhd_bamsize; + zvhd->vhd_header = xmalloc (uae_u8, size); + zfile_fseek (z, 0, SEEK_SET); + if (zfile_fread (zvhd->vhd_header, 1, size, z) != size) + goto end; + zvhd->vhd_sectormap = xmalloc (uae_u8, 512); + zvhd->vhd_sectormapblock = -1; + zvhd->vhd_bitmapsize = ((zvhd->vhd_blocksize / (8 * 512)) + 511) & ~511; + } + z = zfile_fopen_parent (z, NULL, 0, zvhd->virtsize); + z->useparent = 0; + z->dataseek = 1; + z->userdata = zvhd; + z->zfileread = vhd_fread; + write_log (_T("%s is VHD %s image, virtual size=%lldK\n"), + zfile_getname (z), + zvhd->vhd_type == 2 ? _T("fixed") : _T("dynamic"), + zvhd->virtsize / 1024); + return z; +nonvhd: +end: + return z; +} + +static struct zfile *zfile_gunzip (struct zfile *z, int *retcode) +{ + uae_u8 header[2 + 1 + 1 + 4 + 1 + 1]; + z_stream zs; + int i, size, ret, first; + uae_u8 flags; + uae_s64 offset; + TCHAR name[MAX_DPATH]; + uae_u8 buffer[8192]; + struct zfile *z2; + uae_u8 b; + + if (checkwrite (z, retcode)) + return NULL; + _tcscpy (name, z->name); + memset (&zs, 0, sizeof (zs)); + memset (header, 0, sizeof (header)); + zfile_fread (header, sizeof (header), 1, z); + flags = header[3]; + if (header[0] != 0x1f && header[1] != 0x8b) + return NULL; + if (flags & 2) /* multipart not supported */ + return NULL; + if (flags & 32) /* encryption not supported */ + return NULL; + if (flags & 4) { /* skip extra field */ + zfile_fread (&b, 1, 1, z); + size = b; + zfile_fread (&b, 1, 1, z); + size |= b << 8; + zfile_fseek (z, size + 2, SEEK_CUR); + } + + if (flags & 8) { /* get original file name */ + uae_char aname[MAX_DPATH]; + i = 0; + do { + zfile_fread (aname + i, 1, 1, z); + } while (i < MAX_DPATH - 1 && aname[i++]); + aname[i] = 0; + au_copy (name, MAX_DPATH, aname); + } + if (flags & 16) { /* skip comment */ + i = 0; + do { + b = 0; + zfile_fread (&b, 1, 1, z); + } while (b); + } + removeext (name, _T(".gz")); + offset = zfile_ftell (z); + zfile_fseek (z, -4, SEEK_END); + zfile_fread (&b, 1, 1, z); + size = b; + zfile_fread (&b, 1, 1, z); + size |= b << 8; + zfile_fread (&b, 1, 1, z); + size |= b << 16; + zfile_fread (&b, 1, 1, z); + size |= b << 24; + if (size < 8 || size > 256 * 1024 * 1024) /* safety check */ + return NULL; + zfile_fseek (z, offset, SEEK_SET); + z2 = zfile_fopen_empty (z, name, size); + if (!z2) + return NULL; + zs.next_out = z2->data; + zs.avail_out = size; + first = 1; + do { + zs.next_in = buffer; + zs.avail_in = zfile_fread (buffer, 1, sizeof (buffer), z); + if (first) { + if (inflateInit2_ (&zs, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream)) != Z_OK) + break; + first = 0; + } + ret = inflate (&zs, 0); + } while (ret == Z_OK); + inflateEnd (&zs); + if (ret != Z_STREAM_END || first != 0) { + zfile_fclose (z2); + return NULL; + } + zfile_fclose (z); + return z2; +} +struct zfile *zfile_gunzip (struct zfile *z) +{ + return zfile_gunzip (z, NULL); +} + +static void truncate880k (struct zfile *z) +{ + int i; + uae_u8 *b; + + if (z == NULL || z->data == NULL) + return; + if (z->size < 880 * 512 * 2) { + int size = 880 * 512 * 2 - z->size; + b = xcalloc (uae_u8, size); + zfile_fwrite (b, size, 1, z); + xfree (b); + return; + } + for (i = 880 * 512 * 2; i < z->size; i++) { + if (z->data[i]) + return; + } + z->size = 880 * 512 * 2; +} + +static struct zfile *extadf (struct zfile *z, int index, int *retcode) +{ + int i, r; + struct zfile *zo; + uae_u16 *mfm; + uae_u16 *amigamfmbuffer; + uae_u8 writebuffer_ok[32], *outbuf; + int tracks, len, offs, pos; + uae_u8 buffer[2 + 2 + 4 + 4]; + int outsize; + TCHAR newname[MAX_DPATH]; + TCHAR *ext; + int cantrunc = 0; + int done = 0; + + if (index > 1) + return NULL; + + mfm = xcalloc (uae_u16, 32000 / 2); + amigamfmbuffer = xcalloc (uae_u16, 32000 / 2); + outbuf = xcalloc (uae_u8, 16384); + + zfile_fread (buffer, 1, 8, z); + zfile_fread (buffer, 1, 4, z); + tracks = buffer[2] * 256 + buffer[3]; + offs = 8 + 2 + 2 + tracks * (2 + 2 + 4 + 4); + + _tcscpy (newname, zfile_getname (z)); + ext = _tcsrchr (newname, '.'); + if (ext) { + _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".std.adf")); + } else { + _tcscat (newname, _T(".std.adf")); + } + if (index > 0) + _tcscpy (newname + _tcslen (newname) - 4, _T(".ima")); + + zo = zfile_fopen_empty (z, newname, 0); + if (!zo) + goto end; + + if (retcode) + *retcode = 1; + pos = 12; + outsize = 0; + for (i = 0; i < tracks; i++) { + int type, bitlen; + + zfile_fseek (z, pos, SEEK_SET); + zfile_fread (buffer, 2 + 2 + 4 + 4, 1, z); + pos = zfile_ftell (z); + type = buffer[2] * 256 + buffer[3]; + len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7]; + bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11]; + + zfile_fseek (z, offs, SEEK_SET); + if (type == 1) { + zfile_fread (mfm, len, 1, z); + memset (writebuffer_ok, 0, sizeof writebuffer_ok); + memset (outbuf, 0, 16384); + if (index == 0) { + r = isamigatrack (amigamfmbuffer, (uae_u8*)mfm, len, outbuf, writebuffer_ok, i, &outsize); + if (r < 0 && i == 0) { + zfile_seterror (_T("'%s' is not AmigaDOS formatted"), zo->name); + goto end; + } + if (i == 0) + done = 1; + } else { + r = ispctrack (amigamfmbuffer, (uae_u8*)mfm, len, outbuf, writebuffer_ok, i, &outsize); + if (r < 0 && i == 0) { + zfile_seterror (_T("'%s' is not PC formatted"), zo->name); + goto end; + } + if (i == 0) + done = 1; + } + } else { + outsize = 512 * 11; + if (bitlen / 8 > 18000) + outsize *= 2; + zfile_fread (outbuf, outsize, 1, z); + cantrunc = 1; + if (index == 0) + done = 1; + } + zfile_fwrite (outbuf, outsize, 1, zo); + + offs += len; + + } + if (done == 0) + goto end; + zfile_fclose (z); + xfree (mfm); + xfree (amigamfmbuffer); + if (cantrunc) + truncate880k (zo); + return zo; +end: + zfile_fclose (zo); + xfree (mfm); + xfree (amigamfmbuffer); + return NULL; +} + +#ifdef CAPS +#include "caps/caps_win32.h" +static struct zfile *ipf (struct zfile *z, int index, int *retcode) +{ + int i, j, r; + struct zfile *zo; + TCHAR *orgname = zfile_getname (z); + TCHAR *ext = _tcsrchr (orgname, '.'); + TCHAR newname[MAX_DPATH]; + uae_u16 *amigamfmbuffer; + uae_u8 writebuffer_ok[32]; + int tracks, len; + int outsize; + int startpos = 0; + uae_u8 *outbuf; + uae_u8 tmp[12]; + struct zcache *zc; + + if (checkwrite (z, retcode)) + return NULL; + + if (index > 2) + return NULL; + + zc = cache_get (z->name); + if (!zc) { + uae_u16 *mfm; + struct zdiskimage *zd; + if (!caps_loadimage (z, 0, &tracks)) + return NULL; + mfm = xcalloc (uae_u16, 32000 / 2); + zd = xcalloc (struct zdiskimage, 1); + zd->tracks = tracks; + for (i = 0; i < tracks; i++) { + uae_u8 *buf, *p; + int mrev, gapo; + caps_loadtrack (mfm, NULL, 0, i, &len, &mrev, &gapo, NULL, true); + //write_log (_T("%d: %d %d %d\n"), i, mrev, gapo, len); + len /= 8; + buf = p = xmalloc (uae_u8, len); + for (j = 0; j < len / 2; j++) { + uae_u16 v = mfm[j]; + *p++ = v >> 8; + *p++ = v; + } + zd->zdisktracks[i].data = buf; + zd->zdisktracks[i].len = len; + } + caps_unloadimage (0); + zc = zcache_put (z->name, zd); + } + + outbuf = xcalloc (uae_u8, 16384); + amigamfmbuffer = xcalloc (uae_u16, 32000 / 2); + if (ext) { + _tcscpy (newname, orgname); + _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf")); + } else { + _tcscat (newname, _T(".adf")); + } + if (index == 1) + _tcscpy (newname + _tcslen (newname) - 4, _T(".ima")); + if (index == 2) + _tcscpy (newname + _tcslen (newname) - 4, _T(".ext.adf")); + + zo = zfile_fopen_empty (z, newname, 0); + if (!zo) + goto end; + + if (retcode) + *retcode = 1; + + tracks = zc->zd->tracks; + + if (index > 1) { + zfile_fwrite ("UAE-1ADF", 8, 1, zo); + tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */ + tmp[2] = 0; tmp[3] = tracks; /* number of tracks */ + zfile_fwrite (tmp, 4, 1, zo); + memset (tmp, 0, sizeof tmp); + tmp[2] = 0; tmp[3] = 1; /* track type */ + startpos = zfile_ftell (zo); + for (i = 0; i < tracks; i++) + zfile_fwrite (tmp, sizeof tmp, 1, zo); + } + + outsize = 0; + for (i = 0; i < tracks; i++) { + uae_u8 *p = (uae_u8*)zc->zd->zdisktracks[i].data; + len = zc->zd->zdisktracks[i].len; + memset (writebuffer_ok, 0, sizeof writebuffer_ok); + memset (outbuf, 0, 16384); + if (index == 0) { + r = isamigatrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize); + if (r < 0 && i == 0) { + zfile_seterror (_T("'%s' is not AmigaDOS formatted"), orgname); + goto end; + } + zfile_fwrite (outbuf, 1, outsize, zo); + } else if (index == 1) { + r = ispctrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize); + if (r < 0 && i == 0) { + zfile_seterror (_T("'%s' is not PC formatted"), orgname); + goto end; + } + zfile_fwrite (outbuf, outsize, 1, zo); + } else { + int pos = zfile_ftell (zo); + int maxlen = len > 12798 ? len : 12798; + int lenb = len * 8; + + if (maxlen & 1) + maxlen++; + zfile_fseek (zo, startpos + i * 12 + 4, SEEK_SET); + tmp[4] = 0; tmp[5] = 0; tmp[6] = maxlen >> 8; tmp[7] = maxlen; + tmp[8] = lenb >> 24; tmp[9] = lenb >> 16; tmp[10] = lenb >> 8; tmp[11] = lenb; + zfile_fwrite (tmp + 4, 2, 4, zo); + zfile_fseek (zo, pos, SEEK_SET); + zfile_fwrite (p, 1, len, zo); + if (maxlen > len) + zfile_fwrite (outbuf, 1, maxlen - len, zo); + } + } + zfile_fclose (z); + xfree (amigamfmbuffer); + xfree (outbuf); + if (index == 0) + truncate880k (zo); + return zo; +end: + zfile_fclose (zo); + xfree (amigamfmbuffer); + xfree (outbuf); + return NULL; +} +#endif + +#ifdef A_LZX +static struct zfile *dsq (struct zfile *z, int lzx, int *retcode) +{ + struct zfile *zi = NULL; + struct zvolume *zv = NULL; + + if (checkwrite (z, retcode)) + return NULL; + if (lzx) { + zv = archive_directory_lzx (z); + if (zv) { + if (zv->root.child) + zi = archive_access_lzx (zv->root.child); + } + } else { + zi = z; + } + if (zi) { + uae_u8 *buf = zfile_getdata (zi, 0, -1); + if (!memcmp (buf, "PKD\x13", 4) || !memcmp (buf, "PKD\x11", 4)) { + TCHAR *fn; + int sectors = buf[18]; + int reserved = buf[15]; + int blocks = (buf[6] << 8) | buf[7]; + int blocksize = (buf[10] << 8) | buf[11]; + struct zfile *zo; + int size = blocks * blocksize; + int off; + int i; + uae_u8 *bitmap = NULL; + uae_u8 *nullsector; + + nullsector = xcalloc (uae_u8, blocksize); + sectors /= 2; + if (buf[3] == 0x13) { + off = 52; + if (buf[off - 1] == 1) { + bitmap = &buf[off]; + off += (blocks + 7) / 8; + } else if (buf[off - 1] > 1) { + write_log (_T("unknown DSQ extra header type %d\n"), buf[off - 1]); + } + } else { + off = 32; + } + + // some Amiga disk images are smaller than full adf for some reason + if (sectors == 11 && size < 1760 * 512) + size = 1760 * 512; + + if (zfile_getfilename (zi) && _tcslen (zfile_getfilename (zi))) { + fn = xmalloc (TCHAR, (_tcslen (zfile_getfilename (zi)) + 5)); + _tcscpy (fn, zfile_getfilename (zi)); + _tcscat (fn, _T(".adf")); + } else { + fn = my_strdup (_T("dsq.adf")); + } + zo = zfile_fopen_empty (z, fn, size); + xfree (fn); + int seccnt = 0; + for (i = 0; i < blocks; i++) { + int bmoff = i - 2; + int boff = -1; + uae_u32 mask = 0; + if (bitmap) { + boff = (bmoff / 32) * 4; + mask = (bitmap[boff] << 24) | (bitmap[boff + 1] << 16) | (bitmap[boff + 2] << 8) | (bitmap[boff + 3]); + } + if (bmoff >= 0 && boff >= 0 && (mask & (1 << (bmoff & 31)))) { + zfile_fwrite (nullsector, blocksize, 1, zo); + } else { + zfile_fwrite (buf + off, blocksize, 1, zo); + off += blocksize; + seccnt++; + } + if ((i % sectors) == sectors - 1) { + off += seccnt * 16; + seccnt = 0; + } + } + zfile_fclose_archive (zv); + zfile_fclose (z); + xfree (buf); + xfree (nullsector); + return zo; + } + xfree (buf); + } + if (lzx) + zfile_fclose (zi); + return z; +} +#endif + +#ifdef A_WRP +static struct zfile *wrp (struct zfile *z, int *retcode) +{ + if (zfile_needwrite (z)) { + if (retcode) + *retcode = -1; + return NULL; + } + return unwarp (z); +} +#endif + +#ifdef A_DMS +static struct zfile *dms (struct zfile *z, int index, int *retcode) +{ + int ret; + struct zfile *zo; + TCHAR *orgname = zfile_getname (z); + TCHAR *ext = _tcsrchr (orgname, '.'); + TCHAR newname[MAX_DPATH]; + static int recursive; + int i; + struct zfile *zextra[DMS_EXTRA_SIZE] = { 0 }; + + if (checkwrite (z, retcode)) + return NULL; + if (recursive) + return NULL; + if (ext) { + _tcscpy (newname, orgname); + _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf")); + } else { + _tcscat (newname, _T(".adf")); + } + + zo = zfile_fopen_empty (z, newname, 1760 * 512); + if (!zo) + return NULL; + ret = DMS_Process_File (z, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0, 0, zextra); + if (ret == NO_PROBLEM || ret == DMS_FILE_END) { + int off = zfile_ftell (zo); + if (off >= 1760 * 512 / 3 && off <= 1760 * 512 * 3 / 4) { // possible split dms? + if (_tcslen (orgname) > 5) { + TCHAR *s = orgname + _tcslen (orgname) - 5; + if (!_tcsicmp (s, _T("a.dms"))) { + TCHAR *fn2 = my_strdup (orgname); + struct zfile *z2; + fn2[_tcslen (fn2) - 5]++; + recursive++; + z2 = zfile_fopen (fn2, _T("rb"), z->zfdmask); + recursive--; + if (z2) { + ret = DMS_Process_File (z2, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0, 1, NULL); + zfile_fclose (z2); + } + xfree (fn2); + } + } + } + zfile_fseek (zo, 0, SEEK_SET); + if (index > 0) { + zfile_fclose (zo); + zo = NULL; + for (i = 0; i < DMS_EXTRA_SIZE && zextra[i]; i++); + if (index > i) + goto end; + zo = zextra[index - 1]; + zextra[index - 1] = NULL; + } + if (retcode) + *retcode = 1; + zfile_fclose (z); + z = NULL; + + } else { + zfile_fclose (zo); + zo = NULL; + } +end: + for (i = 0; i < DMS_EXTRA_SIZE; i++) + zfile_fclose (zextra[i]); + return zo; +} +#endif + +const TCHAR *uae_ignoreextensions[] = + { _T(".gif"), _T(".jpg"), _T(".png"), _T(".xml"), _T(".pdf"), _T(".txt"), 0 }; +const TCHAR *uae_diskimageextensions[] = + { _T(".adf"), _T(".adz"), _T(".ipf"), _T(".scp"), _T(".fdi"), _T(".exe"), _T(".dms"), _T(".wrp"), _T(".dsq"), 0 }; + +int zfile_is_ignore_ext(const TCHAR *name) +{ + int i; + const TCHAR *ext; + + ext = _tcsrchr (name, '.'); + if (!ext) + return 0; + for (i = 0; uae_ignoreextensions[i]; i++) { + if (!strcasecmp (uae_ignoreextensions[i], ext)) + return 1; + } + return 0; +} + +int zfile_is_diskimage (const TCHAR *name) +{ + int i; + + const TCHAR *ext = _tcsrchr (name, '.'); + if (!ext) + return 0; + i = 0; + while (uae_diskimageextensions[i]) { + if (!strcasecmp (ext, uae_diskimageextensions[i])) + return HISTORY_FLOPPY; + i++; + } + if (!_tcsicmp (ext, _T(".cue"))) + return HISTORY_CD; + return -1; +} + +static const TCHAR *archive_extensions[] = { + _T("7z"), _T("rar"), _T("zip"), _T("lha"), _T("lzh"), _T("lzx"), + _T("adf"), _T("adz"), _T("dsq"), _T("dms"), _T("ipf"), _T("fdi"), _T("wrp"), _T("ima"), + _T("hdf"), _T("tar"), + NULL +}; +static const TCHAR *plugins_7z[] = { _T("7z"), _T("rar"), _T("zip"), _T("lha"), _T("lzh"), _T("lzx"), _T("adf"), _T("dsq"), _T("hdf"), _T("tar"), NULL }; +static const uae_char *plugins_7z_x[] = { "7z", "Rar!", "MK", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static const int plugins_7z_t[] = { + ArchiveFormat7Zip, ArchiveFormatRAR, ArchiveFormatZIP, ArchiveFormatLHA, ArchiveFormatLHA, ArchiveFormatLZX, + ArchiveFormatADF, ArchiveFormatADF, ArchiveFormatADF, ArchiveFormatTAR +}; +static const int plugins_7z_m[] = { + ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, + ZFD_ADF, ZFD_ADF, ZFD_ADF, ZFD_ARCHIVE +}; + +int iszip (struct zfile *z, int mask) +{ + TCHAR *name = z->name; + TCHAR *ext = _tcsrchr (name, '.'); + uae_u8 header[32]; + int i; + + if (!ext) + return 0; + memset (header, 0, sizeof (header)); + zfile_fseek (z, 0, SEEK_SET); + zfile_fread (header, sizeof (header), 1, z); + zfile_fseek (z, 0, SEEK_SET); + + if (mask & ZFD_ARCHIVE) { + if (!strcasecmp (ext, _T(".zip")) || !strcasecmp (ext, _T(".rp9"))) { + if(header[0] == 'P' && header[1] == 'K') + return ArchiveFormatZIP; + return 0; + } + } + if (mask & ZFD_ARCHIVE) { + if (!strcasecmp (ext, _T(".7z"))) { + if(header[0] == '7' && header[1] == 'z') + return ArchiveFormat7Zip; + return 0; + } + if (!strcasecmp (ext, _T(".rar"))) { + if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!') + return ArchiveFormatRAR; + return 0; + } + if (!strcasecmp (ext, _T(".lha")) || !strcasecmp (ext, _T(".lzh"))) { + if(header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-') + return ArchiveFormatLHA; + return 0; + } + if (!strcasecmp (ext, _T(".lzx"))) { + if(header[0] == 'L' && header[1] == 'Z' && header[2] == 'X') + return ArchiveFormatLZX; + return 0; + } + } + if (mask & ZFD_ADF) { + if (!strcasecmp (ext, _T(".adf"))) { + if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) + return ArchiveFormatADF; + if (isfat (header)) + return ArchiveFormatFAT; + return 0; + } + if (!strcasecmp (ext, _T(".ima"))) { + if (isfat (header)) + return ArchiveFormatFAT; + } + } + if (mask & ZFD_HD) { + if (!strcasecmp (ext, _T(".hdf"))) { + if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) + return ArchiveFormatADF; + if (header[0] == 'S' && header[1] == 'F' && header[2] == 'S') + return ArchiveFormatADF; + if (header[0] == 'R' && header[1] == 'D' && header[2] == 'S' && header[3] == 'K') + return ArchiveFormatRDB; + if (isfat (header)) + return ArchiveFormatFAT; + return 0; + } + } +#if defined(ARCHIVEACCESS) + for (i = 0; plugins_7z_x[i]; i++) { + if ((plugins_7z_m[i] & mask) && plugins_7z_x[i] && !strcasecmp (ext + 1, plugins_7z[i]) && + !memcmp (header, plugins_7z_x[i], strlen (plugins_7z_x[i]))) + return plugins_7z_t[i]; + } +#endif + return 0; +} +int iszip (struct zfile *z) +{ + return iszip (z, ZFD_NORMAL); +} + +struct zfile *zuncompress (struct znode *parent, struct zfile *z, int dodefault, int mask, int *retcode, int index) +{ + TCHAR *name = z->name; + TCHAR *ext = NULL; + uae_u8 header[32]; + int i; + + if (retcode) + *retcode = 0; + if (!mask) + return NULL; + if (name) { + ext = _tcsrchr (name, '.'); + if (ext) + ext++; + } + + if (ext != NULL) { + if (mask & ZFD_ARCHIVE) { + if (strcasecmp (ext, _T("7z")) == 0) + return archive_access_select (parent, z, ArchiveFormat7Zip, dodefault, retcode, index); + if (strcasecmp (ext, _T("zip")) == 0) + return archive_access_select (parent, z, ArchiveFormatZIP, dodefault, retcode, index); + if (strcasecmp (ext, _T("lha")) == 0 || strcasecmp (ext, _T("lzh")) == 0) + return archive_access_select (parent, z, ArchiveFormatLHA, dodefault, retcode, index); + if (strcasecmp (ext, _T("lzx")) == 0) + return archive_access_select (parent, z, ArchiveFormatLZX, dodefault, retcode, index); + if (strcasecmp (ext, _T("rar")) == 0) + return archive_access_select (parent, z, ArchiveFormatRAR, dodefault, retcode, index); + if (strcasecmp (ext, _T("tar")) == 0) + return archive_access_select (parent, z, ArchiveFormatTAR, dodefault, retcode, index); + } + if (mask & ZFD_UNPACK) { + if (index == 0) { + if (strcasecmp (ext, _T("gz")) == 0) + return zfile_gunzip (z, retcode); + if (strcasecmp (ext, _T("adz")) == 0) + return zfile_gunzip (z, retcode); + if (strcasecmp (ext, _T("roz")) == 0) + return zfile_gunzip (z, retcode); + if (strcasecmp (ext, _T("hdz")) == 0) + return zfile_gunzip (z, retcode); +#ifdef A_WRP + if (strcasecmp (ext, _T("wrp")) == 0) + return wrp (z, retcode); +#endif + } +#ifdef A_DMS + if (strcasecmp (ext, _T("dms")) == 0) + return dms (z, index, retcode); +#endif + } + if (mask & ZFD_RAWDISK) { +#ifdef CAPS + if (strcasecmp (ext, _T("ipf")) == 0) + return ipf (z, index, retcode); +#endif + if (mask & (ZFD_RAWDISK_PC | ZFD_RAWDISK_AMIGA)) + return NULL; + } +#if defined(ARCHIVEACCESS) + if (index == 0) { + for (i = 0; plugins_7z_x[i]; i++) { + if ((plugins_7z_t[i] & mask) && strcasecmp (ext, plugins_7z[i]) == 0) + return archive_access_arcacc_select (z, plugins_7z_t[i], retcode); + } + } +#endif + } + memset (header, 0, sizeof (header)); + zfile_fseek (z, 0, SEEK_SET); + zfile_fread (header, sizeof (header), 1, z); + zfile_fseek (z, 0, SEEK_SET); + if (!memcmp (header, "conectix", 8)) { + if (index > 0) + return NULL; + return vhd (z); + } + if (mask & ZFD_UNPACK) { + if (index == 0) { + if (header[0] == 0x1f && header[1] == 0x8b) + return zfile_gunzip (z, retcode); +#ifdef A_LZX + if (header[0] == 'P' && header[1] == 'K' && header[2] == 'D') + return dsq (z, 0, retcode); +#endif + } +#ifdef A_DMS + if (header[0] == 'D' && header[1] == 'M' && header[2] == 'S' && header[3] == '!') + return dms (z, index, retcode); +#endif + } + if (mask & ZFD_RAWDISK) { +#ifdef CAPS + if (header[0] == 'C' && header[1] == 'A' && header[2] == 'P' && header[3] == 'S') + return ipf (z, index, retcode); +#endif + if (!memcmp (header, "UAE-1ADF", 8)) + return extadf (z, index, retcode); + } + if (index > 0) + return NULL; + if (mask & ZFD_ARCHIVE) { + if (header[0] == 'P' && header[1] == 'K') + return archive_access_select (parent, z, ArchiveFormatZIP, dodefault, retcode, index); + if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!') + return archive_access_select (parent, z, ArchiveFormatRAR, dodefault, retcode, index); + if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X') + return archive_access_select (parent, z, ArchiveFormatLZX, dodefault, retcode, index); + if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-') + return archive_access_select (parent, z, ArchiveFormatLHA, dodefault, retcode, index); + } + if (mask & ZFD_ADF) { + if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) + return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index); + if (header[0] == 'S' && header[1] == 'F' && header[2] == 'S') + return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index); + if (isfat (header)) + return archive_access_select (parent, z, ArchiveFormatFAT, dodefault, retcode, index); + } + + if (ext) { + if (mask & ZFD_UNPACK) { +#ifdef A_LZX + if (strcasecmp (ext, _T("dsq")) == 0) + return dsq (z, 1, retcode); +#endif + } + if (mask & ZFD_ADF) { + if (strcasecmp (ext, _T("adf")) == 0 && !memcmp (header, "DOS", 3)) + return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index); + } + } + return NULL; +} + +#ifdef SINGLEFILE +extern uae_u8 singlefile_data[]; + +static struct zfile *zfile_opensinglefile(struct zfile *l) +{ + uae_u8 *p = singlefile_data; + int size, offset; + TCHAR tmp[256], *s; + + _tcscpy (tmp, l->name); + s = tmp + _tcslen (tmp) - 1; + while (*s != 0 && *s != '/' && *s != '\\') + s--; + if (s > tmp) + s++; + write_log (_T("loading from singlefile: '%s'\n"), tmp); + while (*p++); + offset = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0); + p += 4; + for (;;) { + size = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0); + if (!size) + break; + if (!strcmpi (tmp, p + 4)) { + l->data = singlefile_data + offset; + l->size = size; + write_log (_T("found, size %d\n"), size); + return l; + } + offset += size; + p += 4; + p += _tcslen (p) + 1; + } + write_log (_T("not found\n")); + return 0; +} +#endif + +static struct zfile *zfile_fopen_nozip (const TCHAR *name, const TCHAR *mode) +{ + struct zfile *l; + FILE *f; + + if(*name == '\0') + return NULL; + l = zfile_create (NULL); + l->name = my_strdup (name); + l->mode = my_strdup (mode); + f = _tfopen (name, mode); + if (!f) { + zfile_fclose (l); + return 0; + } + l->f = f; + return l; +} + + +static struct zfile *openzip (const TCHAR *pname) +{ + int i, j; + TCHAR v; + TCHAR name[MAX_DPATH]; + TCHAR zippath[MAX_DPATH]; + + zippath[0] = 0; + _tcscpy (name, pname); + i = _tcslen (name) - 2; + while (i > 0) { + if ((name[i] == '/' || name[i] == '\\') && i > 4) { + v = name[i]; + name[i] = 0; + for (j = 0; plugins_7z[j]; j++) { + int len = _tcslen (plugins_7z[j]); + if (name[i - len - 1] == '.' && !strcasecmp (name + i - len, plugins_7z[j])) { + struct zfile *f = zfile_fopen_nozip (name, _T("rb")); + if (f) { + f->zipname = my_strdup(name + i + 1); + return f; + } + break; + } + } + name[i] = v; + } + i--; + } + return 0; +} + +static bool writeneeded (const TCHAR *mode) +{ + return _tcschr (mode, 'w') || _tcschr (mode, 'a') || _tcschr (mode, '+') || _tcschr (mode, 't'); +} +bool zfile_needwrite (struct zfile *zf) +{ + if (!zf->mode) + return false; + return writeneeded (zf->mode); +} + +static struct zfile *zfile_fopen_2 (const TCHAR *name, const TCHAR *mode, int mask) +{ + struct zfile *l; + FILE *f; + + if( *name == '\0' ) + return NULL; +#ifdef SINGLEFILE + if (zfile_opensinglefile (l)) + return l; +#endif + l = openzip (name); + if (l) { + if (writeneeded (mode)) { + zfile_fclose (l); + return 0; + } + l->zfdmask = mask; + } else { + struct mystat st; + l = zfile_create (NULL); + l->mode = my_strdup (mode); + l->name = my_strdup (name); + l->zfdmask = mask; + if (!_tcsicmp (mode, _T("r"))) { + f = my_opentext (l->name); + l->textmode = 1; + } else { + f = _tfopen (l->name, mode); + } + if (!f) { + zfile_fclose (l); + return 0; + } + if (my_stat (l->name, &st)) + l->size = st.size; + l->f = f; + } + return l; +} + +#define AF _T("%AMIGAFOREVERDATA%") + +static void manglefilename(TCHAR *out, const TCHAR *in) +{ + int i; + + out[0] = 0; + if (!strncasecmp(in, AF, _tcslen(AF))) + _tcscpy (out, start_path_data); + if ((in[0] == '/' || in[0] == '\\') || (_tcslen(in) > 3 && in[1] == ':' && in[2] == '\\')) + out[0] = 0; + _tcscat(out, in); + for (i = 0; i < _tcslen (out); i++) { + // remove \\ or // in the middle of path + if ((out[i] == '/' || out[i] == '\\') && (out[i + 1] == '/' || out[i + 1] == '\\') && i > 0) { + memmove (out + i, out + i + 1, (_tcslen (out + i) + 1) * sizeof (TCHAR)); + i--; + continue; + } + } +} + +int zfile_zopen (const TCHAR *name, zfile_callback zc, void *user) +{ + struct zfile *l; + int ztype; + TCHAR path[MAX_DPATH]; + + manglefilename(path, name); + l = zfile_fopen_2 (path, _T("rb"), ZFD_NORMAL); + if (!l) + return 0; + ztype = iszip (l); + if (ztype == 0) + zc (l, user); + else + archive_access_scan (l, zc, user, ztype); + zfile_fclose (l); + return 1; +} + +/* + * fopen() for a compressed file + */ +static struct zfile *zfile_fopen_x (const TCHAR *name, const TCHAR *mode, int mask, int index) +{ + int cnt = 10; + struct zfile *l, *l2; + TCHAR path[MAX_DPATH]; + + if (_tcslen (name) == 0) + return NULL; + manglefilename(path, name); + l = zfile_fopen_2 (path, mode, mask); + if (!l) + return 0; + l2 = NULL; + while (cnt-- > 0) { + int rc; + zfile_fseek (l, 0, SEEK_SET); + l2 = zuncompress (NULL, l, 0, mask, &rc, index); + if (!l2) { + if (rc < 0) { + zfile_fclose (l); + return NULL; + } + zfile_fseek (l, 0, SEEK_SET); + break; + } else { + if (l2->parent == l) + l->opencnt--; + } + l = l2; + } + return l; +} + +#ifdef _WIN32 +static int isinternetfile (const TCHAR *name) +{ + if (!_tcsnicmp (name, _T("http://"), 7) || !_tcsnicmp (name, _T("https://"), 8)) + return 1; + if (!_tcsnicmp (name, _T("ftp://"), 6)) + return -1; + return 0; +} +#include +#define INETBUFFERLEN 1000000 +static struct zfile *zfile_fopen_internet (const TCHAR *name, const TCHAR *mode, int mask) +{ + static HINTERNET hi; + HINTERNET i = NULL; + TCHAR tmp[MAX_DPATH]; + DWORD ierr = 0; + DWORD outbuf = sizeof tmp / sizeof (TCHAR); + uae_u8 *data = 0; + int bufferlen = INETBUFFERLEN; + int datalen; + DWORD didread; + struct zfile *zf = NULL; + + if (_tcschr (mode, 'w') || _tcschr (mode, 'a')) + return NULL; + tmp[0] = 0; + if (!hi) { + hi = InternetOpen (WINUAEAPPNAME, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0); + if (hi == NULL) { + write_log (_T("InternetOpen() failed, %d\n"), GetLastError ()); + return NULL; + } + } + i = InternetOpenUrl (hi, name, NULL, 0, INTERNET_FLAG_NO_COOKIES, 0); + if (i == NULL) { + DWORD err = GetLastError (); + if (err == ERROR_INTERNET_EXTENDED_ERROR) + InternetGetLastResponseInfo (&ierr, tmp, &outbuf); + write_log (_T("InternetOpenUrl(%s) failed %d (%d,%s)\n"), name, err, ierr, tmp); + goto end; + } + + if (isinternetfile (name) > 0) { + DWORD statuscode; + DWORD hindex = 0; + DWORD size = sizeof statuscode; + if (!HttpQueryInfo (i, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &statuscode, &size, &hindex)) { + DWORD err = GetLastError (); + write_log (_T("HttpQueryInfo(%s) failed %d\n"), name, err); + goto end; + } + if (statuscode != 200) { + write_log (_T("HttpQueryInfo(%s)=%d\n"), name, statuscode); + goto end; + } + } + + if (mask & ZFD_CHECKONLY) { + zf = zfile_create (NULL); + goto end; + } + + datalen = 0; + data = xmalloc (uae_u8, bufferlen); + for (;;) { + if (!InternetReadFile (i, data + datalen, INETBUFFERLEN, &didread)) { + DWORD err = GetLastError (); + if (err == ERROR_INTERNET_EXTENDED_ERROR) + InternetGetLastResponseInfo (&ierr, tmp, &outbuf); + write_log (_T("InternetReadFile(%s) failed %d (%d,%s)\n"), name, err, ierr, tmp); + break; + } + if (didread == 0) + break; + datalen += didread; + if (datalen > bufferlen - INETBUFFERLEN) { + bufferlen += INETBUFFERLEN; + data = xrealloc (uae_u8, data, bufferlen); + if (!data) { + datalen = 0; + break; + } + } + } + if (datalen > 0) { + zf = zfile_create (NULL); + if (zf) { + zf->size = datalen; + zf->data = data; + data = NULL; + } + } +end: + if (i) + InternetCloseHandle (i); + free (data); + return zf; +} +#endif + +static struct zfile *zfile_fopenx2 (const TCHAR *name, const TCHAR *mode, int mask, int index) +{ + struct zfile *f; + TCHAR tmp[MAX_DPATH]; + +#ifdef _WIN32 + if (isinternetfile (name)) + return zfile_fopen_internet (name, mode, mask); +#endif + f = zfile_fopen_x (name, mode, mask, index); + if (f) + return f; + if (_tcslen (name) <= 2) + return NULL; + if (name[1] != ':') { + _tcscpy (tmp, start_path_data); + _tcscat (tmp, name); + f = zfile_fopen_x (tmp, mode, mask, index); + if (f) + return f; + } +#if 0 + name += 2; + if (name[0] == '/' || name[0] == '\\') + name++; + for (;;) { + _tcscpy (tmp, start_path_data); + _tcscpy (tmp, name); + f = zfile_fopen_x (tmp, mode, mask); + if (f) + return f; + while (name[0]) { + name++; + if (name[-1] == '/' || name[-1] == '\\') + break; + } + if (name[0] == 0) + break; + } +#endif + return NULL; +} + +static struct zfile *zfile_fopenx (const TCHAR *name, const TCHAR *mode, int mask, int index) +{ + struct zfile *zf; + //write_log (_T("zfile_fopen('%s','%s',%08x,%d)\n"), name, mode, mask, index); + zf = zfile_fopenx2 (name, mode, mask, index); + //write_log (_T("=%p\n"), zf); + return zf; +} + +struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode, int mask) +{ + return zfile_fopenx (name, mode, mask, 0); +} +struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode) +{ + return zfile_fopenx (name, mode, 0, 0); +} +struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode, int mask, int index) +{ + return zfile_fopenx (name, mode, mask, index); +} + +struct zfile *zfile_dup (struct zfile *zf) +{ + struct zfile *nzf; + if (!zf) + return NULL; + if (zf->archiveparent) + checkarchiveparent (zf); + if (zf->userdata) + return NULL; + if (!zf->data && zf->dataseek) { + nzf = zfile_create (zf); + } else if (zf->data) { + nzf = zfile_create (zf); + nzf->data = xmalloc (uae_u8, zf->size); + memcpy (nzf->data, zf->data, zf->size); + nzf->size = zf->size; + nzf->datasize = zf->datasize; + } else { + if (zf->zipname) { + nzf = openzip (zf->name); + if (nzf) + return nzf; + } + FILE *ff = _tfopen (zf->name, zf->mode); + if (!ff) + return NULL; + nzf = zfile_create (zf); + nzf->f = ff; + } + zfile_fseek (nzf, zf->seek, SEEK_SET); + if (zf->name) + nzf->name = my_strdup (zf->name); + if (nzf->zipname) + nzf->zipname = my_strdup (zf->zipname); + nzf->zfdmask = zf->zfdmask; + nzf->mode = my_strdup (zf->mode); + nzf->size = zf->size; + return nzf; +} + +int zfile_exists (const TCHAR *name) +{ + struct zfile *z; + + if (my_existsfile (name)) + return 1; + z = zfile_fopen (name, _T("rb"), ZFD_NORMAL | ZFD_CHECKONLY); + if (!z) + return 0; + zfile_fclose (z); + return 1; +} + +int zfile_iscompressed (struct zfile *z) +{ + return z->data ? 1 : 0; +} + +struct zfile *zfile_fopen_empty (struct zfile *prev, const TCHAR *name, uae_u64 size) +{ + struct zfile *l; + l = zfile_create (prev); + l->name = my_strdup (name ? name : _T("")); + if (size) { + l->data = xcalloc (uae_u8, size); + if (!l->data) { + xfree (l); + return NULL; + } + l->size = size; + l->datasize = size; + l->allocsize = size; + } else { + l->data = xcalloc (uae_u8, 1000); + l->size = 0; + l->allocsize = 1000; + } + return l; +} + +struct zfile *zfile_fopen_empty (struct zfile *prev, const TCHAR *name) +{ + return zfile_fopen_empty (prev, name, 0); +} + +struct zfile *zfile_fopen_parent (struct zfile *z, const TCHAR *name, uae_u64 offset, uae_u64 size) +{ + struct zfile *l; + + if (z == NULL) + return NULL; + l = zfile_create (z); + if (name) + l->name = my_strdup (name); + else if (z->name) + l->name = my_strdup (z->name); + l->size = size; + l->datasize = size; + l->offset = offset; + for (;;) { + l->parent = z; + l->useparent = 1; + if (!z->parent) + break; + l->offset += z->offset; + z = z->parent; + } + z->opencnt++; + return l; +} + +struct zfile *zfile_fopen_load_zfile (struct zfile *f) +{ + struct zfile *l = zfile_fopen_empty (f, f->name, f->size); + if (!l) + return NULL; + zfile_fseek (f, 0, SEEK_SET); + zfile_fread (l->data, f->size, 1, f); + return l; +} + +struct zfile *zfile_fopen_data (const TCHAR *name, uae_u64 size, const uae_u8 *data) +{ + struct zfile *l; + l = zfile_create (NULL); + l->name = my_strdup (name ? name : _T("")); + l->data = xmalloc (uae_u8, size); + l->size = size; + l->datasize = size; + memcpy (l->data, data, size); + return l; +} + +uae_u8 *zfile_load_data (const TCHAR *name, const uae_u8 *data,int datalen, int *outlen) +{ + struct zfile *zf, *f; + int size; + uae_u8 *out; + + zf = zfile_fopen_data (name, datalen, data); + f = zfile_gunzip (zf); + size = f->datasize; + zfile_fseek (f, 0, SEEK_SET); + out = xmalloc (uae_u8, size); + zfile_fread (out, 1, size, f); + zfile_fclose (f); + *outlen = size; + return out; +} + +int zfile_truncate (struct zfile *z, uae_s64 size) +{ + if (z->data) { + if (z->size > size) { + z->size = size; + if (z->datasize > z->size) + z->datasize = z->size; + if (z->seek > z->size) + z->seek = z->size; + return 1; + } + return 0; + } else { + /* !!! */ + return 0; + } +} + +uae_s64 zfile_size (struct zfile *z) +{ + return z->size; +} + +uae_s64 zfile_ftell (struct zfile *z) +{ + if (z->data || z->dataseek || z->parent) + return z->seek; + return _ftelli64 (z->f); +} + +uae_s64 zfile_fseek (struct zfile *z, uae_s64 offset, int mode) +{ + if (z->zfileseek) + return z->zfileseek (z, offset, mode); + if (z->data || z->dataseek || (z->parent && z->useparent)) { + int ret = 0; + switch (mode) + { + case SEEK_SET: + z->seek = offset; + break; + case SEEK_CUR: + z->seek += offset; + break; + case SEEK_END: + z->seek = z->size + offset; + break; + } + if (z->seek < 0) { + z->seek = 0; + ret = 1; + } + if (z->seek > z->size) { + z->seek = z->size; + ret = 1; + } + return ret; + } else { + return _fseeki64 (z->f, offset, mode); + } + return 1; +} + +size_t zfile_fread (void *b, size_t l1, size_t l2, struct zfile *z) +{ + if (z->zfileread) + return z->zfileread (b, l1, l2, z); + if (z->data) { + if (z->datasize < z->size && z->seek + l1 * l2 > z->datasize) { + if (z->archiveparent) { + archive_unpackzfile (z); + return zfile_fread (b, l1, l2, z); + } + return 0; + } + if (z->seek + l1 * l2 > z->size) { + if (l1) + l2 = (z->size - z->seek) / l1; + else + l2 = 0; + if (l2 < 0) + l2 = 0; + } + memcpy (b, z->data + z->offset + z->seek, l1 * l2); + z->seek += l1 * l2; + return l2; + } + if (z->parent && z->useparent) { + size_t ret; + uae_s64 v; + uae_s64 size = z->size; + v = z->seek; + if (v + l1 * l2 > size) { + if (l1) + l2 = (size - v) / l1; + else + l2 = 0; + if (l2 < 0) + l2 = 0; + } + zfile_fseek (z->parent, z->seek + z->offset, SEEK_SET); + v = z->seek; + ret = zfile_fread (b, l1, l2, z->parent); + z->seek = v + l1 * ret; + return ret; + } + return fread (b, l1, l2, z->f); +} + +size_t zfile_fwrite (const void *b, size_t l1, size_t l2, struct zfile *z) +{ + if (z->archiveparent) + return 0; + if (z->zfilewrite) + return z->zfilewrite (b, l1, l2, z); + if (z->parent && z->useparent) + return 0; + if (z->data) { + uae_s64 off = z->seek + l1 * l2; + if (z->allocsize == 0) { + write_log (_T("zfile_fwrite(data,%s) but allocsize=0!\n"), z->name); + return 0; + } + if (off > z->allocsize) { + if (z->allocsize < off) + z->allocsize = off; + z->allocsize += z->size / 2; + if (z->allocsize < 10000) + z->allocsize = 10000; + z->data = xrealloc (uae_u8, z->data, z->allocsize); + z->datasize = z->size = off; + } + memcpy (z->data + z->seek, b, l1 * l2); + z->seek += l1 * l2; + if (z->seek > z->size) + z->size = z->seek; + if (z->size > z->datasize) + z->datasize = z->size; + return l2; + } + return fwrite (b, l1, l2, z->f); +} + +size_t zfile_fputs (struct zfile *z, const TCHAR *s) +{ + char *s2 = ua (s); + size_t t; + t = zfile_fwrite (s2, strlen (s2), 1, z); + xfree (s2); + return t; +} + +char *zfile_fgetsa(char *s, int size, struct zfile *z) +{ + checkarchiveparent (z); + if (z->data) { + char *os = s; + int i; + for (i = 0; i < size - 1; i++) { + if (z->seek == z->size) { + if (i == 0) + return NULL; + break; + } + *s = z->data[z->seek++]; + if (*s == '\n') { + s++; + break; + } + s++; + } + *s = 0; + return os; + } else { + return fgets(s, size, z->f); + } +} + +TCHAR *zfile_fgets (TCHAR *s, int size, struct zfile *z) +{ + checkarchiveparent (z); + if (z->data) { + char s2[MAX_DPATH]; + char *p = s2; + int i; + for (i = 0; i < size - 1; i++) { + if (z->seek == z->size) { + if (i == 0) + return NULL; + break; + } + *p = z->data[z->seek++]; + if (*p == 0 && i == 0) + return NULL; + if (*p == '\n' || *p == 0) { + p++; + break; + } + p++; + } + *p = 0; + if (size > strlen (s2) + 1) + size = strlen (s2) + 1; + au_copy (s, size, s2); + return s + size; + } else { + char s2[MAX_DPATH]; + char *s1; + s1 = fgets (s2, size, z->f); + if (!s1) + return NULL; + if (size > strlen (s2) + 1) + size = strlen (s2) + 1; + au_copy (s, size, s2); + return s + size; + } +} + +int zfile_putc (int c, struct zfile *z) +{ + uae_u8 b = (uae_u8)c; + return zfile_fwrite (&b, 1, 1, z) ? 1 : -1; +} + +int zfile_getc (struct zfile *z) +{ + checkarchiveparent (z); + int out = -1; + if (z->data) { + if (z->seek < z->size) { + out = z->data[z->seek++]; + } + } else { + out = fgetc (z->f); + } + return out; +} + +int zfile_ferror (struct zfile *z) +{ + return 0; +} + +uae_u8 *zfile_getdata (struct zfile *z, uae_s64 offset, int len) +{ + uae_s64 pos = zfile_ftell (z); + uae_u8 *b; + if (len < 0) { + zfile_fseek (z, 0, SEEK_END); + len = zfile_ftell (z); + zfile_fseek (z, 0, SEEK_SET); + } + b = xmalloc (uae_u8, len); + zfile_fseek (z, offset, SEEK_SET); + zfile_fread (b, len, 1, z); + zfile_fseek (z, pos, SEEK_SET); + return b; +} + +int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize) +{ + z_stream zs; + int v; + uae_u8 inbuf[4096]; + int incnt; + + memset (&zs, 0, sizeof(zs)); + if (inflateInit_ (&zs, ZLIB_VERSION, sizeof(z_stream)) != Z_OK) + return 0; + zs.next_out = (Bytef*)dst; + zs.avail_out = dstsize; + incnt = 0; + v = Z_OK; + while (v == Z_OK && zs.avail_out > 0) { + if (zs.avail_in == 0) { + int left = srcsize - incnt; + if (left == 0) + break; + if (left > sizeof (inbuf)) + left = sizeof (inbuf); + zs.next_in = inbuf; + zs.avail_in = zfile_fread (inbuf, 1, left, src); + incnt += left; + } + v = inflate (&zs, 0); + } + inflateEnd (&zs); + return 0; +} + +int zfile_zcompress (struct zfile *f, void *src, int size) +{ + int v; + z_stream zs; + uae_u8 outbuf[4096]; + + memset (&zs, 0, sizeof (zs)); + if (deflateInit_ (&zs, Z_DEFAULT_COMPRESSION, ZLIB_VERSION, sizeof(z_stream)) != Z_OK) + return 0; + zs.next_in = (Bytef*)src; + zs.avail_in = size; + v = Z_OK; + while (v == Z_OK) { + zs.next_out = outbuf; + zs.avail_out = sizeof (outbuf); + v = deflate(&zs, Z_NO_FLUSH | Z_FINISH); + if (sizeof(outbuf) - zs.avail_out > 0) + zfile_fwrite (outbuf, 1, sizeof (outbuf) - zs.avail_out, f); + } + deflateEnd(&zs); + return zs.total_out; +} + +TCHAR *zfile_getname (struct zfile *f) +{ + return f ? f->name : NULL; +} + +TCHAR *zfile_getfilename (struct zfile *f) +{ + int i; + if (f->name == NULL) + return NULL; + for (i = _tcslen (f->name) - 1; i >= 0; i--) { + if (f->name[i] == '\\' || f->name[i] == '/' || f->name[i] == ':') { + i++; + return &f->name[i]; + } + } + return f->name; +} + +uae_u32 zfile_crc32 (struct zfile *f) +{ + uae_u8 *p; + int pos, size; + uae_u32 crc; + + if (!f) + return 0; + if (f->data) + return get_crc32 (f->data, f->size); + pos = zfile_ftell (f); + zfile_fseek (f, 0, SEEK_END); + size = zfile_ftell (f); + p = xmalloc (uae_u8, size); + if (!p) + return 0; + memset (p, 0, size); + zfile_fseek (f, 0, SEEK_SET); + zfile_fread (p, 1, size, f); + zfile_fseek (f, pos, SEEK_SET); + crc = get_crc32 (p, size); + xfree (p); + return crc; +} + +static struct zvolume *zvolume_list; + +static void recurparent (TCHAR *newpath, struct znode *zn, int recurse) +{ + if (zn->parent && (&zn->volume->root != zn->parent || zn->volume->parentz == NULL)) { + if (&zn->volume->root == zn->parent && zn->volume->parentz == NULL && !_tcscmp (zn->name, zn->parent->name)) + goto end; + recurparent (newpath, zn->parent, recurse); + } else { + struct zvolume *zv = zn->volume; + if (zv->parentz && recurse) + recurparent (newpath, zv->parentz, recurse); + } +end: + if (newpath[0]) + _tcscat (newpath, FSDB_DIR_SEPARATOR_S); + _tcscat (newpath, zn->name); +} + +static struct znode *znode_alloc(struct znode *parent, const TCHAR *name) +{ + TCHAR fullpath[MAX_DPATH]; + TCHAR tmpname[MAX_DPATH]; + struct znode *zn = xcalloc (struct znode, 1); + struct znode *zn2; + + _tcscpy (tmpname, name); + zn2 = parent->child; + while (zn2) { + if (!_tcscmp (zn2->name, tmpname)) { + TCHAR *ext = _tcsrchr (tmpname, '.'); + if (ext && ext > tmpname + 2 && ext[-2] == '.') { + ext[-1]++; + } else if (ext) { + memmove (ext + 2, ext, (_tcslen (ext) + 1) * sizeof (TCHAR)); + ext[0] = '.'; + ext[1] = '1'; + } else { + int len = _tcslen (tmpname); + tmpname[len] = '.'; + tmpname[len + 1] = '1'; + tmpname[len + 2] = 0; + } + zn2 = parent->child; + continue; + } + zn2 = zn2->sibling; + } + + fullpath[0] = 0; + recurparent (fullpath, parent, FALSE); + _tcscat (fullpath, FSDB_DIR_SEPARATOR_S); + _tcscat (fullpath, tmpname); +#ifdef ZFILE_DEBUG + write_log (_T("znode_alloc vol='%s' parent='%s' name='%s'\n"), parent->volume->root.name, parent->name, name); +#endif + zn->fullname = my_strdup(fullpath); + zn->name = my_strdup(tmpname); + zn->volume = parent->volume; + zn->volume->last->next = zn; + zn->prev = zn->volume->last; + zn->volume->last = zn; + return zn; +} + +static struct znode *znode_alloc_child(struct znode *parent, const TCHAR *name) +{ + struct znode *zn = znode_alloc(parent, name); + + if (!parent->child) { + parent->child = zn; + } else { + struct znode *pn = parent->child; + while (pn->sibling) + pn = pn->sibling; + pn->sibling = zn; + } + zn->parent = parent; + return zn; +} +static struct znode *znode_alloc_sibling(struct znode *sibling, const TCHAR *name) +{ + struct znode *zn = znode_alloc(sibling->parent, name); + + if (!sibling->sibling) { + sibling->sibling = zn; + } else { + struct znode *pn = sibling->sibling; + while (pn->sibling) + pn = pn->sibling; + pn->sibling = zn; + } + zn->parent = sibling->parent; + return zn; +} + +static void zvolume_addtolist(struct zvolume *zv) +{ + if (!zv) + return; + if (!zvolume_list) { + zvolume_list = zv; + } else { + struct zvolume *v = zvolume_list; + while (v->next) + v = v->next; + v->next = zv; + } +} + +static struct zvolume *zvolume_alloc_2 (const TCHAR *name, struct zfile *z, unsigned int id, void *handle, const TCHAR *volname) +{ + struct zvolume *zv = xcalloc (struct zvolume, 1); + struct znode *root; + uae_s64 pos; + int i; + + root = &zv->root; + zv->last = root; + zv->archive = z; + zv->handle = handle; + zv->id = id; + zv->blocks = 4; + if (z) + zv->zfdmask = z->zfdmask; + root->volume = zv; + root->type = ZNODE_DIR; + i = 0; + if (name[0] != '/' && name[0] != '\\' && _tcsncmp (name, _T(".\\"), 2) != 0 && _tcsncmp(name, _T("..\\"), 3) != 0) { + if (_tcschr (name, ':') == 0) { + for (i = _tcslen (name) - 1; i > 0; i--) { + if (name[i] == FSDB_DIR_SEPARATOR) { + i++; + break; + } + } + } + } + root->name = my_strdup (name + i); + root->fullname = my_strdup(name); +#ifdef ZFILE_DEBUG + write_log (_T("created zvolume: '%s' (%s)\n"), root->name, root->fullname); +#endif + if (volname) + zv->volumename = my_strdup (volname); + if (z) { + pos = zfile_ftell(z); + zfile_fseek(z, 0, SEEK_END); + zv->archivesize = zfile_ftell(z); + zfile_fseek(z, pos, SEEK_SET); + } + return zv; +} +struct zvolume *zvolume_alloc (struct zfile *z, unsigned int id, void *handle, const TCHAR *volumename) +{ + return zvolume_alloc_2 (zfile_getname (z), z, id, handle, volumename); +} +struct zvolume *zvolume_alloc_nofile (const TCHAR *name, unsigned int id, void *handle, const TCHAR *volumename) +{ + return zvolume_alloc_2 (name, NULL, id, handle, volumename); +} +struct zvolume *zvolume_alloc_empty (struct zvolume *prev, const TCHAR *name) +{ + struct zvolume *zv = zvolume_alloc_2(name, 0, 0, 0, NULL); + if (!zv) + return NULL; + if (prev) + zv->zfdmask = prev->zfdmask; + return zv; +} + +static struct zvolume *get_zvolume(const TCHAR *path) +{ + struct zvolume *zv = zvolume_list; + while (zv) { + TCHAR *s = zfile_getname (zv->archive); + if (!s) + s = zv->root.name; + if (_tcslen (path) >= _tcslen (s) && !memcmp (path, s, _tcslen (s) * sizeof (TCHAR))) + return zv; + zv = zv->next; + } + return NULL; +} + +static struct zvolume *zfile_fopen_archive_ext (struct znode *parent, struct zfile *zf, int flags) +{ + struct zvolume *zv = NULL; + TCHAR *name = zfile_getname (zf); + TCHAR *ext; + uae_u8 header[7]; + + if (!name) + return NULL; + + memset (header, 0, sizeof (header)); + zfile_fseek (zf, 0, SEEK_SET); + zfile_fread (header, sizeof (header), 1, zf); + zfile_fseek (zf, 0, SEEK_SET); + + ext = _tcsrchr (name, '.'); + if (ext != NULL) { + ext++; + if (flags & ZFD_ARCHIVE) { +#ifdef A_LHA + if (strcasecmp (ext, _T("lha")) == 0 || strcasecmp (ext, _T("lzh")) == 0) + zv = archive_directory_lha (zf); +#endif +#ifdef A_ZIP + if (strcasecmp (ext, _T("zip")) == 0) + zv = archive_directory_zip (zf); +#endif +#ifdef A_7Z + if (strcasecmp (ext, _T("7z")) == 0) + zv = archive_directory_7z (zf); +#endif +#ifdef A_LZX + if (strcasecmp (ext, _T("lzx")) == 0) + zv = archive_directory_lzx (zf); +#endif +#ifdef A_RAR + if (strcasecmp (ext, _T("rar")) == 0) + zv = archive_directory_rar (zf); +#endif + if (strcasecmp (ext, _T("tar")) == 0) + zv = archive_directory_tar (zf); + } + if (flags & ZFD_ADF) { + if (strcasecmp (ext, _T("adf")) == 0 && !memcmp (header, "DOS", 3)) + zv = archive_directory_adf (parent, zf); + } + if (flags & ZFD_HD) { + if (strcasecmp (ext, _T("hdf")) == 0) { + if (!memcmp (header, "RDSK", 4)) + zv = archive_directory_rdb (zf); + else + zv = archive_directory_adf (parent, zf); + } + } + } + return zv; +} + + +static struct zvolume *zfile_fopen_archive_data (struct znode *parent, struct zfile *zf, int flags) +{ + struct zvolume *zv = NULL; + uae_u8 header[32]; + + memset (header, 0, sizeof (header)); + zfile_fread (header, sizeof (header), 1, zf); + zfile_fseek (zf, 0, SEEK_SET); + if (flags & ZFD_ARCHIVE) { +#ifdef A_ZIP + if (header[0] == 'P' && header[1] == 'K') + zv = archive_directory_zip (zf); +#endif +#ifdef A_RAR + if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!') + zv = archive_directory_rar (zf); +#endif +#ifdef A_LZX + if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X') + zv = archive_directory_lzx (zf); +#endif +#ifdef A_LHA + if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-') + zv = archive_directory_lha (zf); +#endif + } + if (flags & ZFD_ADF) { + if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7)) + zv = archive_directory_adf (parent, zf); + } + if (flags & ZFD_HD) { + if (header[0] == 'R' && header[1] == 'D' && header[2] == 'S' && header[3] == 'K') + zv = archive_directory_rdb (zf); + if (isfat (header)) + zv = archive_directory_fat (zf); + } + return zv; +} + +static struct znode *get_znode (struct zvolume *zv, const TCHAR *ppath, int); + +static void zfile_fopen_archive_recurse2 (struct zvolume *zv, struct znode *zn, int flags) +{ + struct zvolume *zvnew; + struct znode *zndir; + TCHAR tmp[MAX_DPATH]; + + _stprintf (tmp, _T("%s.DIR"), zn->fullname + _tcslen (zv->root.name) + 1); + zndir = get_znode(zv, tmp, TRUE); + if (!zndir) { + struct zarchive_info zai = { 0 }; + zvnew = zvolume_alloc_empty (zv, tmp); + zvnew->parentz = zn; + zai.name = tmp; + zai.tv.tv_sec = zn->mtime.tv_sec; + zai.tv.tv_usec = zn->mtime.tv_usec; + zai.comment = zv->volumename; + if (zn->flags < 0) + zai.flags = zn->flags; + zndir = zvolume_adddir_abs(zv, &zai); + zndir->type = ZNODE_VDIR; + zndir->vfile = zn; + zndir->vchild = zvnew; + zvnew->parent = zv; + zndir->offset = zn->offset; + zndir->offset2 = zn->offset2; + } +} + +static int zfile_fopen_archive_recurse (struct zvolume *zv, int flags) +{ + struct znode *zn; + int i, added; + + added = 0; + zn = zv->root.child; + while (zn) { + int done = 0; + struct zfile *z; + TCHAR *ext = _tcsrchr (zn->name, '.'); + if (ext && !zn->vchild && zn->type == ZNODE_FILE) { + for (i = 0; !done && archive_extensions[i]; i++) { + if (!strcasecmp (ext + 1, archive_extensions[i])) { + zfile_fopen_archive_recurse2 (zv, zn, flags); + done = 1; + } + } + } + if (!done) { + z = archive_getzfile (zn, zv->method, 0); + if (z && iszip (z)) + zfile_fopen_archive_recurse2 (zv, zn, flags); + } + zn = zn->next; + } + return 0; +} + + +static struct zvolume *prepare_recursive_volume (struct zvolume *zv, const TCHAR *path, int flags) +{ + struct zfile *zf = NULL; + struct zvolume *zvnew = NULL; + int done = 0; + +#ifdef ZFILE_DEBUG + write_log (_T("unpacking '%s'\n"), path); +#endif + zf = zfile_open_archive (path, 0); + if (!zf) + goto end; + zvnew = zfile_fopen_archive_ext (zv->parentz, zf, flags); + if (!zvnew && !(flags & ZFD_NORECURSE)) { +#if 1 + zvnew = archive_directory_plain (zf); + if (zvnew) { + zfile_fopen_archive_recurse (zvnew, flags); + done = 1; + } +#else + int rc; + int index; + struct zfile *zf2, *zf3; + TCHAR oldname[MAX_DPATH]; + _tcscpy (oldname, zf->name); + index = 0; + for (;;) { + zf3 = zfile_dup (zf); + if (!zf3) + break; + zf2 = zuncompress (&zv->root, zf3, 0, ZFD_ALL, &rc, index); + if (zf2) { + zvnew = archive_directory_plain (zf2); + if (zvnew) { + zvnew->parent = zv->parent; + zfile_fopen_archive_recurse (zvnew); + done = 1; + } + } else { + zfile_fclose (zf3); + if (rc <= 0) + break; + } + index++; + break; // TODO + } +#endif + } else if (zvnew) { + zvnew->parent = zv->parent; + zfile_fopen_archive_recurse (zvnew, flags); + done = 1; + } + if (!done) + goto end; + zfile_fclose_archive(zv); + return zvnew; +end: + write_log (_T("unpack '%s' failed\n"), path); + zfile_fclose_archive (zvnew); + zfile_fclose(zf); + return NULL; +} + +static struct znode *get_znode (struct zvolume *zv, const TCHAR *ppath, int recurse) +{ + struct znode *zn; + TCHAR path[MAX_DPATH], zpath[MAX_DPATH]; + + if (!zv) + return NULL; + _tcscpy (path, ppath); + zn = &zv->root; + while (zn) { + zpath[0] = 0; + recurparent (zpath, zn, recurse); + if (zn->type == ZNODE_FILE) { + if (!_tcsicmp (zpath, path)) + return zn; + } else { + int len = _tcslen (zpath); + if (_tcslen (path) >= len && (path[len] == 0 || path[len] == FSDB_DIR_SEPARATOR) && !_tcsnicmp (zpath, path, len)) { + if (path[len] == 0) + return zn; + if (zn->vchild) { + /* jump to separate tree, recursive archives */ + struct zvolume *zvdeep = zn->vchild; + if (zvdeep->archive == NULL) { + TCHAR newpath[MAX_DPATH]; + newpath[0] = 0; + recurparent (newpath, zn, recurse); +#ifdef ZFILE_DEBUG + write_log (_T("'%s'\n"), newpath); +#endif + zvdeep = prepare_recursive_volume (zvdeep, newpath, ZFD_ALL); + if (!zvdeep) { + write_log (_T("failed to unpack '%s'\n"), newpath); + return NULL; + } + /* replace dummy empty volume with real volume */ + zn->vchild = zvdeep; + zvdeep->parentz = zn; + } + zn = zvdeep->root.child; + } else { + zn = zn->child; + } + continue; + } + } + zn = zn->sibling; + } + return NULL; +} + +static void addvolumesize (struct zvolume *zv, uae_s64 size) +{ + unsigned int blocks = (size + 511) / 512; + + if (blocks == 0) + blocks++; + while (zv) { + zv->blocks += blocks; + zv->size += size; + zv = zv->parent; + } +} + +struct znode *znode_adddir(struct znode *parent, const TCHAR *name, struct zarchive_info *zai) +{ + struct znode *zn; + TCHAR path[MAX_DPATH]; + + path[0] = 0; + recurparent (path, parent, FALSE); + _tcscat (path, FSDB_DIR_SEPARATOR_S); + _tcscat (path, name); + zn = get_znode (parent->volume, path, FALSE); + if (zn) + return zn; + zn = znode_alloc_child(parent, name); + zn->mtime.tv_sec = zai->tv.tv_sec; + zn->mtime.tv_usec = zai->tv.tv_usec; + zn->type = ZNODE_DIR; + if (zai->comment) + zn->comment = my_strdup (zai->comment); + if (zai->flags < 0) + zn->flags = zai->flags; + addvolumesize(parent->volume, 0); + return zn; +} + +struct znode *zvolume_adddir_abs(struct zvolume *zv, struct zarchive_info *zai) +{ + struct znode *zn2; + TCHAR *path = my_strdup(zai->name); + TCHAR *p, *p2; + int i; + + if (_tcslen (path) > 0) { + /* remove possible trailing / or \ */ + TCHAR last; + last = path[_tcslen (path) - 1]; + if (last == '/' || last == '\\') + path[_tcslen (path) - 1] = 0; + } + zn2 = &zv->root; + p = p2 = path; + for (i = 0; path[i]; i++) { + if (path[i] == '/' || path[i] == '\\') { + path[i] = 0; + zn2 = znode_adddir(zn2, p, zai); + path[i] = FSDB_DIR_SEPARATOR; + p = p2 = &path[i + 1]; + } + } + return znode_adddir(zn2, p, zai); +} + +struct znode *zvolume_addfile_abs(struct zvolume *zv, struct zarchive_info *zai) +{ + struct znode *zn, *zn2; + int i; + TCHAR *path = my_strdup (zai->name); + TCHAR *p, *p2; + + zn2 = &zv->root; + p = p2 = path; + for (i = 0; path[i]; i++) { + if (path[i] == '/' || path[i] == '\\') { + path[i] = 0; + zn2 = znode_adddir(zn2, p, zai); + path[i] = FSDB_DIR_SEPARATOR; + p = p2 = &path[i + 1]; + } + } + if (p2) { + zn = znode_alloc_child(zn2, p2); + zn->size = zai->size; + zn->type = ZNODE_FILE; + zn->mtime.tv_sec = zai->tv.tv_sec; + zn->mtime.tv_usec = zai->tv.tv_usec; + if (zai->comment) + zn->comment = my_strdup(zai->comment); + zn->flags = zai->flags; + addvolumesize(zn->volume, zai->size); + } + xfree(path); + return zn; +} + +struct zvolume *zfile_fopen_directory (const TCHAR *dirname) +{ + struct zvolume *zv = NULL; + struct my_opendir_s *dir; + TCHAR fname[MAX_DPATH]; + + dir = my_opendir (dirname); + if (!dir) + return NULL; + zv = zvolume_alloc_nofile (dirname, ArchiveFormatDIR, NULL, NULL); + while (my_readdir (dir, fname)) { + TCHAR fullname[MAX_DPATH]; + struct mystat statbuf; + struct zarchive_info zai = { 0 }; + if (!_tcscmp (fname, _T(".")) || !_tcscmp (fname, _T(".."))) + continue; + _tcscpy (fullname, dirname); + _tcscat (fullname, FSDB_DIR_SEPARATOR_S); + _tcscat (fullname, fname); + if (!my_stat (fullname, &statbuf)) + continue; + zai.name = fname; + zai.size = statbuf.size; + zai.tv.tv_sec = statbuf.mtime.tv_sec; + zai.tv.tv_usec = statbuf.mtime.tv_usec; + if (statbuf.mode & FILEFLAG_DIR) { + zvolume_adddir_abs (zv, &zai); + } else { + struct znode *zn; + zn = zvolume_addfile_abs (zv, &zai); + //zfile_fopen_archive_recurse2 (zv, zn); + } + } + my_closedir (dir); + // zfile_fopen_archive_recurse (zv); + if (zv) + zvolume_addtolist (zv); + return zv; +} + +struct zvolume *zfile_fopen_archive (const TCHAR *filename, int flags) +{ + struct zvolume *zv = NULL; + struct zfile *zf = zfile_fopen_nozip (filename, _T("rb")); + + if (!zf) + return NULL; + zf->zfdmask = flags; + zv = zfile_fopen_archive_ext (NULL, zf, flags); + if (!zv) + zv = zfile_fopen_archive_data (NULL, zf, flags); +#if 0 + if (!zv) { + struct zfile *zf2 = zuncompress (zf, 0, 0); + if (zf2 != zf) { + zf = zf2; + zv = zfile_fopen_archive_ext(zf, flags); + if (!zv) + zv = zfile_fopen_archive_data(zf, flags); + } + } +#endif + /* pointless but who cares? */ + if (!zv && !(flags & ZFD_NORECURSE)) + zv = archive_directory_plain (zf); + +#if RECURSIVE_ARCHIVES + if (zv && !(flags & ZFD_NORECURSE)) + zfile_fopen_archive_recurse (zv, flags); +#endif + + if (zv) + zvolume_addtolist (zv); + else + zfile_fclose(zf); + return zv; +} +struct zvolume *zfile_fopen_archive (const TCHAR *filename) +{ + return zfile_fopen_archive (filename, ZFD_ALL); +} + +struct zvolume *zfile_fopen_archive_root (const TCHAR *filename, int flags) +{ + TCHAR path[MAX_DPATH], *p1, *p2, *lastp; + struct zvolume *zv = NULL; + //int last = 0; + int num, i; + + if (my_existsdir (filename)) + return zfile_fopen_directory (filename); + + num = 1; + lastp = NULL; + for (;;) { + _tcscpy (path, filename); + p1 = p2 = path; + for (i = 0; i < num; i++) { + while (*p1 != FSDB_DIR_SEPARATOR && *p1 != 0) + p1++; + if (*p1 == 0 && p1 == lastp) + return NULL; + if (i + 1 < num) + p1++; + } + *p1 = 0; + lastp = p1; + if (my_existsfile (p2)) + return zfile_fopen_archive (p2, flags); + num++; + } + +#if 0 + while (!last) { + while (*p1 != FSDB_DIR_SEPARATOR && *p1 != 0) + p1++; + if (*p1 == 0) + last = 1; + *p1 = 0; + if (!zv) { + zv = zfile_fopen_archive (p2); + if (!zv) + return NULL; + } else { + struct znode *zn = get_znode (zv, p2); + if (!zn) + return NULL; + } + p2 = p1 + 1; + } + return zv; +#endif +} + +void zfile_fclose_archive(struct zvolume *zv) +{ + struct znode *zn; + struct zvolume *v; + + if (!zv) + return; + zn = &zv->root; + while (zn) { + struct znode *zn2 = zn->next; + if (zn->vchild) + zfile_fclose_archive(zn->vchild); + xfree(zn->comment); + xfree(zn->fullname); + xfree(zn->name); + zfile_fclose(zn->f); + memset (zn, 0, sizeof (struct znode)); + if (zn != &zv->root) + xfree(zn); + zn = zn2; + } + archive_access_close (zv->handle, zv->id); + if (zvolume_list == zv) { + zvolume_list = zvolume_list->next; + } else { + v = zvolume_list; + while (v) { + if (v->next == zv) { + v->next = zv->next; + break; + } + v = v->next; + } + } + xfree(zv); +} + +struct zdirectory { + TCHAR *parentpath; + struct znode *first; + struct znode *n; + bool doclose; + struct zvolume *zv; + int cnt; + int offset; + TCHAR **filenames; +}; + +struct zdirectory *zfile_opendir_archive (const TCHAR *path, int flags) +{ + struct zvolume *zv = get_zvolume(path); + bool created = false; + if (zv == NULL) { + zv = zfile_fopen_archive (path, flags); + created = true; + } + struct znode *zn = get_znode(zv, path, TRUE); + struct zdirectory *zd; + + if (!zn || (!zn->child && !zn->vchild)) { + if (created) + zfile_fclose_archive (zv); + return NULL; + } + zd = xcalloc (struct zdirectory, 1); + if (created) + zd->zv = zv; + if (zn->child) { + zd->n = zn->child; + } else { + if (zn->vchild->archive == NULL) { + struct zvolume *zvnew = prepare_recursive_volume (zn->vchild, path, flags); + if (zvnew) { + zn->vchild = zvnew; + zvnew->parentz = zn; + } + } + zd->n = zn->vchild->root.next; + } + zd->parentpath = my_strdup (path); + zd->first = zd->n; + return zd; +} +struct zdirectory *zfile_opendir_archive (const TCHAR *path) +{ + return zfile_opendir_archive (path, ZFD_ALL | ZFD_NORECURSE); +} +void zfile_closedir_archive(struct zdirectory *zd) +{ + if (!zd) + return; + zfile_fclose_archive (zd->zv); + xfree (zd->parentpath); + xfree (zd->filenames); + xfree(zd); +} +int zfile_readdir_archive (struct zdirectory *zd, TCHAR *out, bool fullpath) +{ + if (out) + out[0] = 0; + if (!zd->n || (zd->filenames != NULL && zd->offset >= zd->cnt)) + return 0; + if (zd->filenames == NULL) { + struct znode *n = zd->first; + int cnt = 0, len = 0; + while (n) { + cnt++; + n = n->sibling; + } + n = zd->first; + uae_u8 *buf = xmalloc (uae_u8, cnt * sizeof (TCHAR*)); + zd->filenames = (TCHAR**)buf; + buf += cnt * sizeof (TCHAR*); + for (int i = 0; i < cnt; i++) { + zd->filenames[i] = n->name; + n = n->sibling; + } + for (int i = 0; i < cnt; i++) { + for (int j = i + 1; j < cnt; j++) { + if (_tcscmp (zd->filenames[i], zd->filenames[j]) > 0) { + TCHAR *tmp = zd->filenames[i]; + zd->filenames[i] = zd->filenames[j]; + zd->filenames[j] = tmp; + } + } + } + zd->cnt = cnt; + } + if (out == NULL) + return zd->cnt; + if (fullpath) { + _tcscpy (out, zd->parentpath); + _tcscat (out, FSDB_DIR_SEPARATOR_S); + } + _tcscat (out, zd->filenames[zd->offset]); + zd->offset++; + return 1; +} +int zfile_readdir_archive (struct zdirectory *zd, TCHAR *out) +{ + return zfile_readdir_archive (zd, out, false); +} + +struct zfile *zfile_readdir_archive_open (struct zdirectory *zd, const TCHAR *mode) +{ + TCHAR path[MAX_DPATH]; + if (!zfile_readdir_archive (zd, path, true)) + return NULL; + return zfile_fopen (path, mode, ZFD_ARCHIVE | ZFD_NORECURSE); +} + + +void zfile_resetdir_archive (struct zdirectory *zd) +{ + zd->offset = 0; + zd->n = zd->first; +} + +int zfile_fill_file_attrs_archive(const TCHAR *path, int *isdir, int *flags, TCHAR **comment) +{ + struct zvolume *zv = get_zvolume(path); + struct znode *zn = get_znode (zv, path, TRUE); + + *isdir = 0; + *flags = 0; + if (comment) + *comment = 0; + if (!zn) + return 0; + if (zn->type == ZNODE_DIR) + *isdir = 1; + else if (zn->type == ZNODE_VDIR) + *isdir = -1; + *flags = zn->flags; + if (zn->comment && comment) + *comment = my_strdup(zn->comment); + return 1; +} + +int zfile_fs_usage_archive(const TCHAR *path, const TCHAR *disk, struct fs_usage *fsp) +{ + struct zvolume *zv = get_zvolume(path); + + if (!zv) + return -1; + fsp->fsu_blocks = zv->blocks; + fsp->fsu_bavail = 0; + return 0; +} + +int zfile_stat_archive (const TCHAR *path, struct mystat *s) +{ + struct zvolume *zv = get_zvolume(path); + struct znode *zn = get_znode (zv, path, TRUE); + + memset (s, 0, sizeof (struct mystat)); + if (!zn) + return 0; + s->size = zn->size; + s->mtime.tv_sec = zn->mtime.tv_sec; + s->mtime.tv_usec = zn->mtime.tv_usec; + return 1; +} + +uae_s64 zfile_lseek_archive (struct zfile *d, uae_s64 offset, int whence) +{ + uae_s64 old = zfile_ftell (d); + if (old < 0 || zfile_fseek (d, offset, whence)) + return -1; + return old; +} +uae_s64 zfile_fsize_archive (struct zfile *d) +{ + return zfile_size (d); +} + +unsigned int zfile_read_archive (struct zfile *d, void *b, unsigned int size) +{ + return zfile_fread (b, 1, size, d); +} + +void zfile_close_archive (struct zfile *d) +{ + /* do nothing, keep file cached */ +} + +struct zfile *zfile_open_archive (const TCHAR *path, int flags) +{ + struct zvolume *zv = get_zvolume(path); + struct znode *zn = get_znode (zv, path, TRUE); + struct zfile *z; + + if (!zn) + return 0; + if (zn->f) { + zfile_fseek(zn->f, 0, SEEK_SET); + return zn->f; + } + if (zn->vfile) + zn = zn->vfile; + z = archive_getzfile (zn, zn->volume->id, 0); + if (z) + zfile_fseek(z, 0, SEEK_SET); + zn->f = z; + return zn->f; +} + +int zfile_exists_archive (const TCHAR *path, const TCHAR *rel) +{ + TCHAR tmp[MAX_DPATH]; + struct zvolume *zv; + struct znode *zn; + + _stprintf (tmp, _T("%s%c%s"), path, FSDB_DIR_SEPARATOR, rel); + zv = get_zvolume(tmp); + zn = get_znode (zv, tmp, TRUE); + return zn ? 1 : 0; +} + +int zfile_convertimage (const TCHAR *src, const TCHAR *dst) +{ + struct zfile *s, *d; + int ret = 0; + + s = zfile_fopen (src, _T("rb"), ZFD_NORMAL); + if (s) { + uae_u8 *b; + int size; + zfile_fseek (s, 0, SEEK_END); + size = zfile_ftell (s); + zfile_fseek (s, 0, SEEK_SET); + b = xcalloc (uae_u8, size); + if (b) { + if (zfile_fread (b, size, 1, s) == 1) { + d = zfile_fopen (dst, _T("wb"), 0); + if (d) { + if (zfile_fwrite (b, size, 1, d) == 1) + ret = 1; + zfile_fclose (d); + } + } + xfree (b); + } + zfile_fclose (s); + } + return ret; +} + +#ifdef _CONSOLE +static TCHAR *zerror; +#define WRITE_LOG_BUF_SIZE 4096 +void zfile_seterror (const TCHAR *format, ...) +{ + int count; + if (!zerror) { + TCHAR buffer[WRITE_LOG_BUF_SIZE]; + va_list parms; + va_start (parms, format); + count = _vsntprintf (buffer, WRITE_LOG_BUF_SIZE - 1, format, parms); + zerror = my_strdup (buffer); + va_end (parms); + } +} +TCHAR *zfile_geterror (void) +{ + return zerror; +} +#else +void zfile_seterror (const TCHAR *format, ...) +{ +} +#endif