DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #ifndef DOSBOX_DOSBOX_H 00021 #define DOSBOX_DOSBOX_H 00022 00023 #include "config.h" 00024 #include "logging.h" 00025 00026 #if defined(C_ICONV) 00027 /* good */ 00028 #elif defined(C_ICONV_WIN32) 00029 /* good */ 00030 #else 00031 /* auto-pick */ 00032 #if defined(_WIN32) || defined(WINDOWS) 00033 #define C_ICONV_WIN32 1 /* use the Win32 API */ 00034 #else 00035 #pragma warning "iconv backend not chosen, will become mandatory at some point" 00036 #endif 00037 #endif 00038 00039 /* Mac OS X: There seems to be a problem with Macbooks where the touchpad 00040 is seen by SDL2 as a "touchscreen", even though the screen is 00041 not a touchscreen. The result is DOSBox-X getting mixed messages 00042 from both the mouse cursor and the touch pad, which makes the 00043 interface unusable. The solution is to ignore touch events on 00044 Mac OS X. 00045 00046 Perhaps if DOSBox-X is someday ported to run on an iPad (with 00047 a touchscreen) this can be made conditional to allow touch 00048 events there. */ 00049 #if defined(C_SDL2) && defined(MACOSX) 00050 # define IGNORE_TOUCHSCREEN 00051 #endif 00052 00053 /* SANITY CHECK */ 00054 #if defined(C_HEAVY_DEBUG) && !defined(C_DEBUG) 00055 # error If C_HEAVY_DEBUG is defined, then so must C_DEBUG 00056 #endif 00057 /* ------------ */ 00058 00059 #if defined(_MSC_VER) 00060 # include <sys/types.h> 00061 # include <sys/stat.h> 00062 00063 /* Microsoft has their own stat/stat64 scheme */ 00064 # define pref_stat _stati64 00065 # define pref_struct_stat struct _stat64 00066 #else 00067 /* As long as FILE_OFFSET_BITS==64 Linux is quite good at allowing stat to work with 64-bit sizes */ 00068 # define pref_stat stat 00069 # define pref_struct_stat struct stat 00070 #endif 00071 00072 // TODO: The autoconf script should test the size of long double 00073 #if defined(_MSC_VER) 00074 // Microsoft C++ sizeof(long double) == sizeof(double) 00075 #elif defined(__arm__) 00076 // ARMv7 (Raspberry Pi) does not have long double, sizeof(long double) == sizeof(double) 00077 #else 00078 // GCC, other compilers, have sizeof(long double) == 10 80-bit IEEE 00079 # define HAS_LONG_DOUBLE 1 00080 #endif 00081 00082 GCC_ATTRIBUTE(noreturn) void E_Exit(const char * format,...) GCC_ATTRIBUTE( __format__(__printf__, 1, 2)); 00083 00084 typedef Bits cpu_cycles_count_t; 00085 typedef Bitu cpu_cycles_countu_t; 00086 00087 #include "clockdomain.h" 00088 00089 class Config; 00090 class Section; 00091 00092 #if defined(__GNUC__) 00093 # define DEPRECATED __attribute__((deprecated)) 00094 #else 00095 # define DEPRECATED 00096 #endif 00097 00098 enum MachineType { 00099 MCH_HERC, 00100 MCH_CGA, 00101 MCH_TANDY, 00102 MCH_PCJR, 00103 MCH_EGA, 00104 MCH_VGA, 00105 MCH_AMSTRAD, 00106 MCH_PC98, 00107 00108 MCH_FM_TOWNS, // STUB!! 00109 00110 MCH_MCGA, // IBM PS/2 model 30 Multi-Color Graphics Adapter 00111 MCH_MDA 00112 }; 00113 00114 enum SVGACards { 00115 SVGA_None, 00116 SVGA_S3Trio, 00117 SVGA_TsengET4K, 00118 SVGA_TsengET3K, 00119 SVGA_ParadisePVGA1A 00120 }; 00121 00122 typedef Bitu (LoopHandler)(void); 00123 00124 extern Config* control; 00125 extern SVGACards svgaCard; 00126 extern MachineType machine; 00127 extern bool SDLNetInited, uselfn; 00128 extern bool mono_cga; 00129 extern bool DEPRECATED mainline_compatible_mapping; 00130 extern bool DEPRECATED mainline_compatible_bios_mapping; 00131 00132 #ifdef __SSE__ 00133 extern bool sse1_available; 00134 extern bool sse2_available; 00135 #endif 00136 00137 void MSG_Add(const char*,const char*); //add messages to the internal languagefile 00138 const char* MSG_Get(char const *); //get messages from the internal languagefile 00139 00140 void DOSBOX_RunMachine(); 00141 void DOSBOX_SetLoop(LoopHandler * handler); 00142 void DOSBOX_SetNormalLoop(); 00143 00144 /* machine tests for use with if() statements */ 00145 #define IS_TANDY_ARCH ((machine==MCH_TANDY) || (machine==MCH_PCJR)) 00146 #define IS_EGAVGA_ARCH ((machine==MCH_EGA) || (machine==MCH_VGA)) 00147 #define IS_EGA_ARCH (machine==MCH_EGA) 00148 #define IS_VGA_ARCH (machine==MCH_VGA) 00149 #define IS_PC98_ARCH (machine==MCH_PC98) 00150 00151 #define IS_FM_TOWNS (machine==MCH_FM_TOWNS) 00152 00153 /* machine tests for use with switch() statements */ 00154 #define TANDY_ARCH_CASE MCH_TANDY: case MCH_PCJR 00155 #define EGAVGA_ARCH_CASE MCH_EGA: case MCH_VGA 00156 #define VGA_ARCH_CASE MCH_VGA 00157 #define PC98_ARCH_CASE MCH_PC98 00158 00159 #define FM_TOWNS_ARCH_CASE MCH_FM_TOWNS 00160 00161 #ifndef DOSBOX_LOGGING_H 00162 #include "logging.h" 00163 #endif // the logging system. 00164 00165 extern ClockDomain clockdom_PCI_BCLK; 00166 extern ClockDomain clockdom_ISA_OSC; 00167 extern ClockDomain clockdom_ISA_BCLK; 00168 00169 signed long long time_to_clockdom(ClockDomain &src,double t); 00170 unsigned long long update_clockdom_from_now(ClockDomain &dst); 00171 00172 extern bool enable_pc98_jump; 00173 00174 enum { 00175 UTF8ERR_INVALID=-1, 00176 UTF8ERR_NO_ROOM=-2 00177 }; 00178 00179 #ifndef UNICODE_BOM 00180 #define UNICODE_BOM 0xFEFF 00181 #endif 00182 00183 int utf8_encode(char **ptr,const char *fence,uint32_t code); 00184 int utf8_decode(const char **ptr,const char *fence); 00185 int utf16le_encode(char **ptr,const char *fence,uint32_t code); 00186 int utf16le_decode(const char **ptr,const char *fence); 00187 00188 typedef char utf8_t; 00189 typedef uint16_t utf16_t; 00190 00191 /* for DOS filename handling we want a toupper that uses the MS-DOS code page within not the locale of the host */ 00192 int ascii_toupper(int c); 00193 00194 enum { 00195 BOOTHAX_NONE=0, 00196 BOOTHAX_MSDOS 00197 }; 00198 00199 extern Bit32u guest_msdos_LoL; 00200 extern Bit16u guest_msdos_mcb_chain; 00201 extern int boothax; 00202 00203 /* C++11 user-defined literal, to help with byte units */ 00204 typedef unsigned long long bytecount_t; 00205 00206 static inline constexpr bytecount_t operator "" _bytes(const bytecount_t x) { 00207 return x; 00208 } 00209 00210 static inline constexpr bytecount_t operator "" _parabytes(const bytecount_t x) { /* AKA bytes per segment increment in real mode */ 00211 return x << bytecount_t(4u); 00212 } 00213 00214 static inline constexpr bytecount_t operator "" _kibibytes(const bytecount_t x) { 00215 return x << bytecount_t(10u); 00216 } 00217 00218 static inline constexpr bytecount_t operator "" _pagebytes(const bytecount_t x) { /* bytes per 4KB page in protected mode */ 00219 return x << bytecount_t(12u); 00220 } 00221 00222 static inline constexpr bytecount_t operator "" _mibibytes(const bytecount_t x) { 00223 return x << bytecount_t(20u); 00224 } 00225 00226 static inline constexpr bytecount_t operator "" _gibibytes(const bytecount_t x) { 00227 return x << bytecount_t(30u); 00228 } 00229 00230 static inline constexpr bytecount_t operator "" _tebibytes(const bytecount_t x) { 00231 return x << bytecount_t(40u); 00232 } 00233 00234 /* and the same, for variables */ 00235 00236 static inline constexpr bytecount_t _bytes(const bytecount_t x) { 00237 return x; 00238 } 00239 00240 static inline constexpr bytecount_t _parabytes(const bytecount_t x) { /* AKA bytes per segment increment in real mode */ 00241 return x << bytecount_t(4u); 00242 } 00243 00244 static inline constexpr bytecount_t _kibibytes(const bytecount_t x) { 00245 return x << bytecount_t(10u); 00246 } 00247 00248 static inline constexpr bytecount_t _pagebytes(const bytecount_t x) { /* bytes per 4KB page in protected mode */ 00249 return x << bytecount_t(12u); 00250 } 00251 00252 static inline constexpr bytecount_t _mibibytes(const bytecount_t x) { 00253 return x << bytecount_t(20u); 00254 } 00255 00256 static inline constexpr bytecount_t _gibibytes(const bytecount_t x) { 00257 return x << bytecount_t(30u); 00258 } 00259 00260 static inline constexpr bytecount_t _tebibytes(const bytecount_t x) { 00261 return x << bytecount_t(40u); 00262 } 00263 00264 #endif /* DOSBOX_DOSBOX_H */ 00265 00266 #ifndef SAVE_STATE_H_INCLUDED 00267 #define SAVE_STATE_H_INCLUDED 00268 00269 #include <sstream> 00270 #include <map> 00271 #include <algorithm> 00272 #include <functional> 00273 #include <vector> 00274 00275 00276 #define WRITE_POD(x,y) \ 00277 stream.write(reinterpret_cast<const char*>( (x) ), sizeof( (y) ) ); 00278 00279 #define WRITE_POD_SIZE(x,y) \ 00280 stream.write(reinterpret_cast<const char*>( (x) ), (y) ); 00281 00282 #define READ_POD(x,y) \ 00283 stream.read(reinterpret_cast<char*>( (x) ), sizeof( (y) ) ); 00284 00285 #define READ_POD_SIZE(x,y) \ 00286 stream.read(reinterpret_cast<char*>( (x) ), (y) ); 00287 00288 00289 00290 class SaveState 00291 { 00292 public: 00293 static SaveState& instance(); 00294 00295 typedef std::string Error; 00296 static const size_t SLOT_COUNT = 10; //slot: [0,...,SLOT_COUNT - 1] 00297 00298 void save (size_t slot); //throw (Error) 00299 void load (size_t slot) const; //throw (Error) 00300 bool isEmpty(size_t slot) const; 00301 std::string getName(size_t slot) const; 00302 00303 //initialization: register relevant components on program startup 00304 struct Component 00305 { 00306 virtual void getBytes(std::ostream& stream) = 0; 00307 virtual void setBytes(std::istream& stream) = 0; 00308 }; 00309 00310 void registerComponent(const std::string& uniqueName, Component& comp); //comp must have global lifetime! 00311 00312 private: 00313 SaveState() {} 00314 SaveState(const SaveState&); 00315 SaveState& operator=(const SaveState&); 00316 00317 class RawBytes 00318 { 00319 public: 00320 RawBytes() : dataExists(false), isCompressed(false) {} 00321 void set(const std::string& stream); 00322 std::string get() const; //throw (Error) 00323 void compress() const; //throw (Error) 00324 bool dataAvailable() const; 00325 private: 00326 bool dataExists; //determine whether set method (even with empty string) was called 00327 mutable bool isCompressed; //design for logical not binary const 00328 mutable std::string bytes; // 00329 }; 00330 00331 struct CompData 00332 { 00333 CompData(Component& cmp) : comp(cmp), rawBytes(SLOT_COUNT) {} 00334 Component& comp; 00335 std::vector<RawBytes> rawBytes; 00336 }; 00337 00338 typedef std::map<std::string, CompData> CompEntry; 00339 CompEntry components; 00340 }; 00341 00342 00343 //some helper functions 00344 template <class T> 00345 void writePOD(std::ostream& stream, const T& data); 00346 00347 template <class T> 00348 void readPOD(std::istream& stream, T& data); 00349 00350 void writeString(std::ostream& stream, const std::string& data); 00351 void readString(std::istream& stream, std::string& data); 00352 00353 00354 //Implementation of SaveState::Component for saving POD types only 00355 class SerializeGlobalPOD : public SaveState::Component 00356 { 00357 public: 00358 SerializeGlobalPOD(const std::string& compName) 00359 { 00360 SaveState::instance().registerComponent(compName, *this); 00361 } 00362 00363 template <class T> 00364 void registerPOD(T& pod) //register POD for serializatioin 00365 { 00366 podRef.push_back(POD(pod)); 00367 } 00368 00369 protected: 00370 virtual void getBytes(std::ostream& stream) 00371 { 00372 std::for_each(podRef.begin(), podRef.end(), std::bind1st(WriteGlobalPOD(), &stream)); 00373 } 00374 00375 virtual void setBytes(std::istream& stream) 00376 { 00377 std::for_each(podRef.begin(), podRef.end(), std::bind1st(ReadGlobalPOD(), &stream)); 00378 } 00379 00380 private: 00381 struct POD 00382 { 00383 template <class T> 00384 POD(T& pod) : address(&pod), size(sizeof(T)) {} 00385 void* address; 00386 size_t size; 00387 }; 00388 00389 struct WriteGlobalPOD : public std::binary_function<std::ostream*, POD, void> 00390 { 00391 void operator()(std::ostream* stream, const POD& data) const 00392 { 00393 stream->write(static_cast<const char*>(data.address), data.size); 00394 } 00395 }; 00396 00397 struct ReadGlobalPOD : public std::binary_function<std::istream*, POD, void> 00398 { 00399 void operator()(std::istream* stream, const POD& data) const 00400 { 00401 stream->read(static_cast<char*>(data.address), data.size); 00402 } 00403 }; 00404 00405 std::vector<POD> podRef; 00406 }; 00407 00408 //---------------- inline implementation ------------------------- 00409 template <class T> 00410 inline 00411 void writePOD(std::ostream& stream, const T& data) 00412 { 00413 stream.write(reinterpret_cast<const char*>(&data), sizeof(T)); 00414 } 00415 00416 00417 template <class T> 00418 inline 00419 void readPOD(std::istream& stream, T& data) 00420 { 00421 stream.read(reinterpret_cast<char*>(&data), sizeof(T)); 00422 } 00423 00424 00425 inline 00426 void writeString(std::ostream& stream, const std::string& data) 00427 { 00428 const size_t stringSize = data.size(); 00429 writePOD(stream, stringSize); 00430 stream.write(data.c_str(), stringSize * sizeof(std::string::value_type)); 00431 } 00432 00433 00434 inline 00435 void readString(std::istream& stream, std::string& data) 00436 { 00437 size_t stringSize = 0; 00438 readPOD(stream, stringSize); 00439 data.resize(stringSize); 00440 stream.read(&data[0], stringSize * sizeof(std::string::value_type)); 00441 } 00442 #endif //SAVE_STATE_H_INCLUDED