From 04a295b23dafe98e79b17724f5fc1e010a3775da Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Tue, 19 Mar 2024 23:35:31 +0100 Subject: [PATCH] 2022-07-31: Updated to version 1.65 Signed-off-by: Gwenhael Le Moine --- CONVERT.EXE | Bin 0 -> 45056 bytes Convert.exe | Bin 32768 -> 0 bytes Emu48.exe | Bin 319488 -> 319488 bytes Emu48.htm | 167 +++++++----- Emu48.url | 2 +- MKSHARED.EXE | Bin 32768 -> 0 bytes MKSHARED.exe | Bin 0 -> 45056 bytes PROBLEMS.TXT | 4 +- Sources/Convert/CONVERT.DSP | 100 +++++++ Sources/Convert/CONVERT.DSW | 29 ++ Sources/Convert/CONVERT.MAK | 184 ------------- Sources/Convert/CONVERT.MDP | Bin 34816 -> 0 bytes Sources/Convert/MAIN.C | 78 ++++-- Sources/Emu48/CHANGES.TXT | 66 +++++ Sources/Emu48/EMU48.C | 29 +- Sources/Emu48/EMU48.H | 5 +- Sources/Emu48/EMU48.RC | 12 +- Sources/Emu48/EMU48.sln | 31 +++ Sources/Emu48/ENGINE.C | 9 +- Sources/Emu48/EXTERNAL.C | 99 ------- Sources/Emu48/Emu48.vcxproj | 352 ++++++++++++++++++++++++ Sources/Emu48/Emu48.vcxproj.filters | 169 ++++++++++++ Sources/Emu48/Emu48.vcxproj.user | 4 + Sources/Emu48/FILES.C | 50 ++-- Sources/Emu48/LODEPNG.C | 405 +++++++++++++++++++--------- Sources/Emu48/LODEPNG.H | 108 ++++++-- Sources/Emu48/MOPS.C | 11 +- Sources/Emu48/MRU.C | 45 +++- Sources/Emu48/PCH.H | 1 + Sources/Emu48/SERIAL.C | 7 +- Sources/GCCPatch/EMU48GCC.RC | 12 +- Sources/GCCPatch/PCH.H | 2 + Sources/GCCPatch/README.TXT | 2 +- Sources/MkShared/MKSHARED.C | 39 ++- Sources/MkShared/MKSHARED.DSP | 26 +- Sources/MkShared/MKSHARED.RC | 10 +- uninst.exe | Bin 66820 -> 66820 bytes 37 files changed, 1442 insertions(+), 616 deletions(-) create mode 100755 CONVERT.EXE delete mode 100755 Convert.exe delete mode 100755 MKSHARED.EXE create mode 100755 MKSHARED.exe create mode 100644 Sources/Convert/CONVERT.DSP create mode 100644 Sources/Convert/CONVERT.DSW delete mode 100644 Sources/Convert/CONVERT.MAK delete mode 100644 Sources/Convert/CONVERT.MDP create mode 100644 Sources/Emu48/EMU48.sln delete mode 100644 Sources/Emu48/EXTERNAL.C create mode 100644 Sources/Emu48/Emu48.vcxproj create mode 100644 Sources/Emu48/Emu48.vcxproj.filters create mode 100644 Sources/Emu48/Emu48.vcxproj.user diff --git a/CONVERT.EXE b/CONVERT.EXE new file mode 100755 index 0000000000000000000000000000000000000000..eb46d29a2fee48a1fd7ccfe9e2cb300189d9dae9 GIT binary patch literal 45056 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 literal 0 HcmV?d00001 diff --git a/Convert.exe b/Convert.exe deleted file mode 100755 index 01117ec87fb60fdcf5b76a4e2fcb177958deddd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 delta 27499 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

1. General

2. Acknowledgements

-

3. ROM Images

+

3. ROM Images
+ 3.1 Creation examples

4. Installation

5. How to Start

6. Command Line

@@ -87,7 +88,7 @@ h3 { color:red; font-size:1.1em; }

1. General

-

Emu48 is an +

Emu48 is an emulator for the Hewlett Packard HP38G, HP39G, HP40G, HP48SX, HP48GX and HP49G calculator hardware. These calculators are based on the 1LT8 Clarke (HP48SX) and on the Yorke chip.

@@ -126,73 +127,97 @@ h3 { color:red; font-size:1.1em; } in the destination file with zeros. Final notice, the convert utility shows the CRC result after the file convert and a passed ROM CRC test does not imply, that the source file - is in an Emu48 suitable format! + is in an Emu48 suitable format! To create a ROM image in a suitable + format, call the convert utility with the 2nd file argument.

-
    -
  • HP38 -

    To upload the ROM of your HP38G, you will need a special aplet - called "ROM UPLOAD". - Once you've uploaded the ROM, you have to convert it using the - Convert utility.

    -

    To do that, start a Command Prompt while running Windows, and - type:

    -
    Convert <rom-file> ROM.38G
    -

    Where <rom-file> is the path to your ROM image. This will - create a file named ROM.38G. This tool will also check its validity. -

  • -
  • HP39/40 -

    To upload the ROM of your HP39G/HP40G, you will need a special aplet - called "ROM UPLOAD". - Once you've uploaded the ROM, you have to convert it using the Rom2emu utility. -

    -

    To do that, start a Command Prompt while running Windows, and - type:

    -
    Rom2emu <rom-file> ROM.39G
    -

    There's also a HP39G/HP40G beta ROM for emulators inside an old - Emu48 package. -

  • -
  • HP48 -

    If you have already used another HP48 emulator, you can convert - the ROM using the Convert utility. -

    -

    To do that, start a Command Prompt while running Windows, and - type:

    -
    Convert <rom-file> ROM.48G
    -

    or

    -
    Convert <rom-file> ROM.48S
    -

    Where <rom-file> is the path to your old ROM image. This - will create a file named ROM.48G or ROM.48S, depending on the version - you own. This tool should be able to read any style of ROM image, and - will also check its validity. Note that if you run it with only one - parameter, no file will be written, but it will still check the - validity of the ROM.

    -

    If you have never used an HP48 emulator, and don't have a ROM - dump, you can either use Jean-Yves Avenard's ROMUPL.BIN or the - ROMDump Wizard V1.x, which will almost automatically get the ROM from - your HP48. After the download you may have to convert your dump with - the CONVERT utility into the Emu48 format.

    -

    You can find the latest version of the ROM dump programs on:

    -
    - ROMUPL.BIN - http://www.hpcalc.org/details.php?id=3686
    - ROMDump Wizard - - http://hp.giesselink.com/emu48.htm -
  • -
  • HP49G -

    There's no ROM download program available so far. But you can - create a ROM image with the - UPD49ROM tool - and a - ROM update file for the HP49G calculator. I suggested to use - version 1.19-6 -

    -

    To create a HP49G ROM image file, start a Command Prompt while - running Windows, and type:

    -
    UPD49ROM -f hp49119-6.flash ROM.49G
    -

    This will create a HP49G ROM image file with an empty User - Port 2.

  • -
+

The general syntax of the convert utility is:

+
Convert [-p] <old-rom-dump> [<new-rom-dump>]
+

where:

+
Convert <old-rom-dump>
+

check if <old-rom-dump> is in a known source format and + report the ROM Model, the ROM Version and the result of the CRC + check. +

+

where:

+
Convert <old-rom-dump> <new-rom-dump>
+

convert the file <old-rom-dump> into the unpacked + ROM image file <new-rom-dump> valid for use in Emu48. +

+

where:

+
Convert -p <old-rom-dump> <new-rom-dump>
+

convert the file <old-rom-dump> into the packed + ROM image file <new-rom-dump> valid for use in Emu48. +

+

3.1 Creation examples

+
    +
  • HP38 +

    To upload the ROM of your HP38G, you will need a special aplet + called "ROM UPLOAD". + Once you've uploaded the ROM, you have to convert it using the + Convert utility.

    +

    To do that, start a Command Prompt while running Windows, and + type:

    +
    Convert -p <rom-file> ROM.38G
    +

    Where <rom-file> is the path to your ROM image. This will + create a packed file named ROM.38G. This tool will also check its validity. +

  • +
  • HP39/40 +

    To upload the ROM of your HP39G/HP40G, you will need a special aplet + called "ROM UPLOAD". + Once you've uploaded the ROM, you may convert it to the unpacked format + using the Rom2emu utility or rename it when you want to keep the packed + format. +

    +

    To do that, start a Command Prompt while running Windows, and + type:

    +
    Rom2emu <rom-file> ROM.39G
    +

    or

    +
    rename <rom-file> ROM.39G
    +

    There's also a HP39G/HP40G beta ROM for emulators inside an old + Emu48 package. +

  • +
  • HP48 +

    If you have already used another HP48 emulator, you can convert + the ROM using the Convert utility. +

    +

    To do that, start a Command Prompt while running Windows, and + type:

    +
    Convert <rom-file> ROM.48G
    +

    or

    +
    Convert <rom-file> ROM.48S
    +

    Where <rom-file> is the path to your old ROM image. This + will create a file named ROM.48G or ROM.48S, depending on the + version you own. This tool should be able to read any style of + ROM image, and will also check its validity. Note that if you run + it with only one parameter, no file will be written, but it will + still check the validity of the ROM.

    +

    If you have never used an HP48 emulator, and don't have a ROM + dump, you can either use Jean-Yves Avenard's ROMUPL.BIN or the + ROMDump Wizard V1.x, which will almost automatically get the ROM + from your HP48. After the download you may have to convert your + dump with the CONVERT utility into the Emu48 format.

    +

    You can find the latest version of the ROM dump programs on:

    +
    + ROMUPL.BIN + http://www.hpcalc.org/details.php?id=3686
    + ROMDump Wizard + + https://hp.giesselink.com/emu48.htm +
  • +
  • HP49G +

    There's no ROM download program available so far. But you can + create a ROM image with the + UPD49ROM tool + and a + ROM update file for the HP49G calculator. I suggested to use + version 1.19-6 +

    +

    To create a HP49G ROM image file, start a Command Prompt while + running Windows, and type:

    +
    UPD49ROM -f hp49119-6.flash ROM.49G
    +

    This will create a HP49G ROM image file with an empty User + Port 2.

  • +

4. Installation

To install Emu48 you may use the installer package which contain, among the binaries, some HP48 KML scripts or just unzip the emulator @@ -238,7 +263,7 @@ h3 { color:red; font-size:1.1em; }

If you want other great scripts, visit Rechlin's great HP archive

If you are interested in writing new scripts, get the KML 2.0 - documentation from the + documentation from the authors Emu48 page.

Having selected a script, press OK to start the emulator. In most cases, when Emu48 crash after pressing the OK button, you are using @@ -461,7 +486,7 @@ h3 { color:red; font-size:1.1em; } simulation. The data transfer to the printer simulator is done over UDP. In this section you can the define the IPv4 address and the port the printer simulator is listening. A suitable HP82240B printer simulation can - be found here.

+ be found here.

8.6.3.3 Section Serial Ports

  • Wire @@ -611,7 +636,7 @@ h3 { color:red; font-size:1.1em; }

    14. License

    Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator
    - Copyright (C) 2020 Christoph Gießelink

    + Copyright (C) 2022 Christoph Gießelink

    This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) diff --git a/Emu48.url b/Emu48.url index 2ccd2f4..620d662 100644 --- a/Emu48.url +++ b/Emu48.url @@ -1,2 +1,2 @@ [InternetShortcut] -URL=http://hp.giesselink.com/ +URL=https://hp.giesselink.com/ diff --git a/MKSHARED.EXE b/MKSHARED.EXE deleted file mode 100755 index 6662fba46f7ac7b35b48ebe10eef740fc07bdff3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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�P#%iOMOV-KGp$tw)TUu5bb7-<-%+ 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 tI}^{zCn +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=CONVERT - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "CONVERT.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "CONVERT.mak" CFG="CONVERT - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CONVERT - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "CONVERT - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "CONVERT - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "CONVERT - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "CONVERT - Win32 Release" +# Name "CONVERT - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\MAIN.C +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Sources/Convert/CONVERT.DSW b/Sources/Convert/CONVERT.DSW new file mode 100644 index 0000000..40aa0b7 --- /dev/null +++ b/Sources/Convert/CONVERT.DSW @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CONVERT"=.\CONVERT.DSP - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Sources/Convert/CONVERT.MAK b/Sources/Convert/CONVERT.MAK deleted file mode 100644 index f87b86f..0000000 --- a/Sources/Convert/CONVERT.MAK +++ /dev/null @@ -1,184 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Format Version 40001 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -!IF "$(CFG)" == "" -CFG=Convert - Win32 Debug -!MESSAGE No configuration specified. Defaulting to Convert - Win32 Debug. -!ENDIF - -!IF "$(CFG)" != "Convert - Win32 Release" && "$(CFG)" !=\ - "Convert - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE on this makefile -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Convert.mak" CFG="Convert - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Convert - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "Convert - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF -################################################################################ -# Begin Project -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Convert - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -OUTDIR=.\Release -INTDIR=.\Release - -ALL : "$(OUTDIR)\Convert.exe" - -CLEAN : - -@erase ".\Release\Convert.exe" - -@erase ".\Release\Main.obj" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c -CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ - /Fp"$(INTDIR)/Convert.pch" /YX /Fo"$(INTDIR)/" /c -CPP_OBJS=.\Release/ -CPP_SBRS= -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x40c /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -BSC32_FLAGS=/nologo /o"$(OUTDIR)/Convert.bsc" -BSC32_SBRS= -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:console /machine:I386 -LINK32_FLAGS=kernel32.lib /nologo /subsystem:console /incremental:no\ - /pdb:"$(OUTDIR)/Convert.pdb" /machine:I386 /out:"$(OUTDIR)/Convert.exe" -LINK32_OBJS= \ - "$(INTDIR)/Main.obj" - -"$(OUTDIR)\Convert.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "Convert - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -OUTDIR=.\Debug -INTDIR=.\Debug - -ALL : "$(OUTDIR)\Convert.exe" - -CLEAN : - -@erase ".\Debug\Convert.exe" - -@erase ".\Debug\Main.obj" - -@erase ".\Debug\Convert.ilk" - -@erase ".\Debug\Convert.pdb" - -@erase ".\Debug\vc40.pdb" - -@erase ".\Debug\vc40.idb" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c -CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ - /Fp"$(INTDIR)/Convert.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c -CPP_OBJS=.\Debug/ -CPP_SBRS= -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x40c /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -BSC32_FLAGS=/nologo /o"$(OUTDIR)/Convert.bsc" -BSC32_SBRS= -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:console /debug /machine:I386 -LINK32_FLAGS=kernel32.lib /nologo /subsystem:console /incremental:yes\ - /pdb:"$(OUTDIR)/Convert.pdb" /debug /machine:I386 /out:"$(OUTDIR)/Convert.exe" -LINK32_OBJS= \ - "$(INTDIR)/Main.obj" - -"$(OUTDIR)\Convert.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - -.c{$(CPP_OBJS)}.obj: - $(CPP) $(CPP_PROJ) $< - -.cpp{$(CPP_OBJS)}.obj: - $(CPP) $(CPP_PROJ) $< - -.cxx{$(CPP_OBJS)}.obj: - $(CPP) $(CPP_PROJ) $< - -.c{$(CPP_SBRS)}.sbr: - $(CPP) $(CPP_PROJ) $< - -.cpp{$(CPP_SBRS)}.sbr: - $(CPP) $(CPP_PROJ) $< - -.cxx{$(CPP_SBRS)}.sbr: - $(CPP) $(CPP_PROJ) $< - -################################################################################ -# Begin Target - -# Name "Convert - Win32 Release" -# Name "Convert - Win32 Debug" - -!IF "$(CFG)" == "Convert - Win32 Release" - -!ELSEIF "$(CFG)" == "Convert - Win32 Debug" - -!ENDIF - -################################################################################ -# Begin Source File - -SOURCE=.\Main.c - -"$(INTDIR)\Main.obj" : $(SOURCE) "$(INTDIR)" - - -# End Source File -# End Target -# End Project -################################################################################ diff --git a/Sources/Convert/CONVERT.MDP b/Sources/Convert/CONVERT.MDP deleted file mode 100644 index 1d00d245f6392096023c372db53ad888e97aac54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34816 zcmeI5-BS}+6u?jT5=0S|4{fWxrL|R2fVHHhVL>8wAHX zcBYU0u%Ayp^sx_p>_hv|8KzI2=|ACX`_$>XL(ko0lL!Q*1`Oov%qE+A&OP_s-@O~m z@#N&n#7K8F)IbQJ3h1af0;_aXG=YZ|J$st`TW}tN@G2Yw$)d@9Br26d!25&uPvuOR zW?Dd?2KGVYR50-VL|=DTY$`Ar{k<`>CxZT9XD7t3TH+(FI-lMZU@mgYiN}=tcnyaE zVgNrp!0Vrc1;??|k9cisd{OrKSzgD3LiSm?d%y>97SCGL@}9k&$ASa#nAc4X<#m%o z>1LO@y4noENxtNSggVKSDMN8Mz`1OHw7Tw1%QO8e{*(3)o`U)9bi!V?9iALeg=q_e zGrw-C7Ef~1QH%i-RZ?1FpktgHT(P-7s89L(HKsv8cxU)4j|;lEm{m^WV^! ze+=6~ti$bvPT}Q;Zr|)R+MO7ShVj*Ksw2b`>ACzY)Ol?F0PPHmtVpV9`D>No_^p0} zbuaaGtIV(EjicaX&M~jM$0uQ{9kT1a1#X$#=W`0G;FCB@vMF$Ze0z`la5CI}k0R+<3 zzA9fcz%S74o)s`rUFc znm_|o%eYgW8<^8@D)PLJ(SiHedZb`#=VU|z4;fVO^!8O}^jtyq!PBcL(DUpS>ivN) zzQ+?y?cpm23%<#QdMr-Y)TiH*QX296Jn%sg0PlC>@ zG>i%s<4IvHd#xw1^=QN}_?%*}h-o`kS}nA93gyQ}g{k5UbTh3aFaWm@s}^>|b>iAa>+}d!nlf&!?H%yJ%JEP%irsKkaE)%eJBAG_XfB6W zwUZCqW4dYyTg*BPlUUcUv)rRKxV4*7<05&pd+E~faA26t9I$Usam&VCc(Z$^rBK#+ zS|1#|aAu}%T5;6*3m6D@FM7O-Uhkq0;9oSp3bE*wD1et`n9U_D7DtqK8s-1VRiT3j z5CI}U1c(3;D1QPJ|11ABA`gi`F#;6-D@LX=+JCDW!u-$rT>fW2W^RoNhbe}^#4K~> zIlHBsnz&^%-ORic)`FcHX*Pdh8}ogivI#o{1<@YzZCza?|*ymiu6nbhyW2F0z`latS3P6-}OwWg$V2x z0u=we!d2$FzWFJoQ5-S7CLif^|og;vRYmQ8r=Aw%=~L#Ta|D;91Ramgx$J? z3%PoJv1qm|A(j#x>seclaI|PS!gXa83kwo@!i~R%>={Kb^K}KqxOT&K2I5$radc9az?{XbL_0pDC3REBbX2TbnYQAAH0H>r+)$P7t8@-%e02-!UlvvwYWPCp`PO>JzHpyc3|ybc`MOZbY66XJ;a9*NK=J=l{QlFk2Ab)&q4Gb;Me%wbyx@z diff --git a/Sources/Convert/MAIN.C b/Sources/Convert/MAIN.C index ec3e2a6..461673d 100644 --- a/Sources/Convert/MAIN.C +++ b/Sources/Convert/MAIN.C @@ -79,7 +79,7 @@ static BYTE Asc2Nib(char c) return 0; } -static DWORD Asc2Nib5(LPSTR lpBuf) +static DWORD Asc2Nib5(LPBYTE lpBuf) { return ( ((DWORD)Asc2Nib(lpBuf[0])<<16) @@ -104,7 +104,6 @@ UINT main(int argc, char *argv[]) LPBYTE pIn; DWORD dwSizeLo; BYTE szVersion[16]; - DWORD dwWritten; UINT i,uLen; DWORD dwAddress; @@ -116,39 +115,53 @@ UINT main(int argc, char *argv[]) BOOL bSwap = FALSE; BOOL bText = FALSE; BOOL bDA19 = FALSE; + BOOL bPack = FALSE; - if ((argc!=2)&&(argc!=3)) + int iArg = 1; // first argument + + if (argc < 2 || argc > 4) { - printf("Usage:\n\t%s []\n", argv[0]); + printf("Usage:\n\t%s [-p] []\n", argv[0]); return 1; } - pRom = LocalAlloc(LMEM_FIXED,512*1024*2); + + while (*argv[iArg] == '-') // an option + { + if (strcmp(argv[iArg],"-p") == 0) // option "-p", pack result ROM image + { + bPack = TRUE; // pack target ROM image + --argc; // option is not an argument + } + ++iArg; // first file argument + } + + pRom = (LPBYTE) malloc(512*1024*2); if (pRom == NULL) { printf("Memory Allocation Failed !"); return 1; } - hFile = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + hFile = CreateFile(argv[iArg],GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile == INVALID_HANDLE_VALUE) { - LocalFree(pRom); - printf("Cannot open file %s.\n", argv[1]); + free(pRom); + printf("Cannot open file %s.\n", argv[iArg]); return 1; } dwSizeLo = GetFileSize(hFile, NULL); - hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMap == NULL) { - LocalFree(pRom); + free(pRom); CloseHandle(hFile); puts("CreateFileMapping failed."); return 1; } - pIn = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + pIn = (LPBYTE) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (pIn == NULL) { - LocalFree(pRom); + free(pRom); CloseHandle(hMap); CloseHandle(hFile); puts("MapViewOfFile failed.\n"); @@ -195,7 +208,7 @@ UINT main(int argc, char *argv[]) if (!bFormatDetected) { - LocalFree(pRom); + free(pRom); UnmapViewOfFile(pIn); CloseHandle(hMap); CloseHandle(hFile); @@ -335,7 +348,7 @@ UINT main(int argc, char *argv[]) printf("ROM Version : %s\n", szVersion); - ZeroMemory(pRom+0x100, 0x40); // clear IO register area + ZeroMemory(pRom+0x100, 0x40); // clear IO register area if (CheckCRC()) { @@ -345,21 +358,44 @@ UINT main(int argc, char *argv[]) { printf("ROM CRC Test FAILED !\n"); } - - if (argc == 3) + + if (argc == 3) // write target file { - hOut = CreateFile(argv[2],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + DWORD dwWritten; + + // size of target file + DWORD dwRomSize = (wType != HP48S)?(512*1024*2):(256*1024*2); + + hOut = CreateFile(argv[iArg+1],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile == INVALID_HANDLE_VALUE) { - LocalFree(pRom); - printf("Cannot open file %s.\n", argv[2]); + free(pRom); + printf("Cannot open file %s.\n", argv[iArg+1]); return 1; } - WriteFile(hOut,pRom,(wType != HP48S)?(512*1024*2):(256*1024*2),&dwWritten,NULL); + + if (bPack) // pack target ROM image + { + LPBYTE pbySrc,pbyDest; + DWORD i; + + dwRomSize /= 2; // packed image has half of size + + // pack data + pbySrc = pbyDest = pRom; + for (i = 0; i < dwRomSize; i++) + { + *pbyDest = *pbySrc++; + *pbyDest |= *pbySrc++ << 4; + pbyDest++; + } + } + + WriteFile(hOut,pRom,dwRomSize,&dwWritten,NULL); CloseHandle(hOut); } - LocalFree(pRom); + free(pRom); return 0; } diff --git a/Sources/Emu48/CHANGES.TXT b/Sources/Emu48/CHANGES.TXT index 91f8686..dab5a6f 100644 --- a/Sources/Emu48/CHANGES.TXT +++ b/Sources/Emu48/CHANGES.TXT @@ -1,3 +1,69 @@ +Service Pack 65 for Emu48 Version 1.0 + +EMU48.C +- changed function SettingsPeripheralProc(), get the COM port state + over function CommIsOpen() now +- changed function SaveChanges(), added document name to MRU list +- changed function OnFileMruOpen(), modified implementation taking + care of the SaveChanges() modification adding a filename to the + MRU list after saving a document + +EMU48.H +- changed function prototype +- extern declaration of global functions +- removed extern declaration of global variable + +EMU48.RC +- changed version and copyright + +ENGINE.C +- removed global variable bCommInit +- changed function CheckSerial(), get the COM port state over + function CommIsOpen() now +- changed function WorkerThread(), removed bCommInit setting + +FILES.C +- changed function DibNumColors(), CreateBIPalette() and + DecodeBmp(), marked BITMAPINFOHEADER pointer as unaligned +- changed function CreateBIPalette() and DecodeBmp(), minor + optimization at input data check +- changed function DecodePng(), simplified destination row pointer + calculation in main loop and removed dead code in function + cleanup + +LODEPNG.C +- changed implementation file to LodePNG version 20220717 with + unmarked typecast patches for x64 compatibility, Copyright (c) + 2005-2022 Lode Vandevenne + +LODEPNG.H +- changed header file to LodePNG version 20220717 + +MOPS.C +- bugfix in function ReadIO(), the RBF (Receive Buffer Full) bit was + cleared before the content of the RBR LSB (0x114) and RBR MSB + (0x115) register was read, so the serial port event thread + overwrote the RBR register with new data in some conditions +- bugfix in function WriteIO(), fixed implementation of the EIRU + bit in the IRC (0x11A) register + +MRU.C +- added some remarks +- added function MruID(), return ID of the given entry +- changed function MruFilename(), changed function interface writing + found filename into a buffer instead of returning a pointer to the + filename + +PCH.H +- added __unaligned definition for MSVC6.0 SDK and earlier + +SERIAL.C +- added new function CommIsOpen(), return if COM port open +- bugfix in function CommReceive(), the ReadFile() buffer argument + was a BYTE** instead of a BYTE* (the wrong argument type was fixed + by the compiler) + + Service Pack 64 for Emu48 Version 1.0 DEBUGGER.C diff --git a/Sources/Emu48/EMU48.C b/Sources/Emu48/EMU48.C index 8c5a121..7af76f8 100644 --- a/Sources/Emu48/EMU48.C +++ b/Sources/Emu48/EMU48.C @@ -13,7 +13,7 @@ #include "kml.h" #include "debugger.h" -#define VERSION "1.64" +#define VERSION "1.65" #ifdef _DEBUG LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug"); @@ -681,13 +681,13 @@ static INT_PTR CALLBACK SettingsPeripheralProc(HWND hDlg, UINT uMsg, WPARAM wPar // set combobox parameter SetCommList(hDlg,szSerialWire,szSerialIr); - if (bCommInit) // disable when port open + if (CommIsOpen()) // disable when port open { EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE); EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); } - if (cCurrentRomType=='X') // HP49G + if (cCurrentRomType=='X') // HP49G { SendDlgItemMessage(hDlg,IDC_IR,CB_RESETCONTENT,0,0); EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); @@ -768,7 +768,10 @@ static UINT SaveChanges(BOOL bAuto) if (GetSaveAsFilename()) { if (SaveDocumentAs(szBufferFilename)) + { + MruAdd(szBufferFilename); return IDYES; + } else return IDCANCEL; } @@ -776,6 +779,7 @@ static UINT SaveChanges(BOOL bAuto) } SaveDocument(); + MruAdd(szCurrentFilename); return IDYES; } @@ -1050,25 +1054,32 @@ cancel: // static LRESULT OnFileMruOpen(UINT wID) { - LPCTSTR lpszFilename; + TCHAR szFilename[MAX_PATH]; wID -= ID_FILE_MRU_FILE1; // zero based MRU index - lpszFilename = MruFilename(wID); // full filename from MRU list - if (lpszFilename == NULL) return 0; // MRU slot not filled + + // full filename from MRU list + MruFilename(wID,szFilename,ARRAYSIZEOF(szFilename)); + if (*szFilename == 0) return 0; // MRU slot not filled if (bDocumentAvail) { SwitchToState(SM_INVALID); + // saving may change MRU index and destroy lpszFilename pointer content if (IDCANCEL == SaveChanges(bAutoSave)) goto cancel; } - if (!OpenDocument(lpszFilename)) // document loading failed + if (!OpenDocument(szFilename)) // document loading failed { - MruRemove(wID); // entry not valid any more + wID = MruID(szFilename); // get actual MRU ID after saving + if (wID != (UINT) -1) // entry still in MRU list + { + MruRemove(wID); // entry not valid any more + } } else { - MruMoveTop(wID); // move entry to top of MRU list + MruAdd(szFilename); // add entry to top of MRU list } cancel: if (pbyRom) SwitchToState(SM_RUN); diff --git a/Sources/Emu48/EMU48.H b/Sources/Emu48/EMU48.H index 9d5e957..570e62c 100644 --- a/Sources/Emu48/EMU48.H +++ b/Sources/Emu48/EMU48.H @@ -134,7 +134,8 @@ extern VOID MruAdd(LPCTSTR lpszEntry); extern VOID MruRemove(UINT nIndex); extern VOID MruMoveTop(UINT nIndex); extern UINT MruEntries(VOID); -extern LPCTSTR MruFilename(UINT nIndex); +extern UINT MruID(LPCTSTR lpszEntry); +extern VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize); extern VOID MruUpdateMenu(HMENU hMenu); extern VOID MruWriteList(VOID); extern VOID MruReadList(VOID); @@ -193,7 +194,6 @@ extern BOOL bRealSpeed; extern BOOL bKeySlow; extern BOOL bSoundSlow; extern UINT nOpcSlow; -extern BOOL bCommInit; extern CHIPSET Chipset; extern TCHAR szSerialWire[16]; extern TCHAR szSerialIr[16]; @@ -407,6 +407,7 @@ extern LPCTSTR RplGetName(DWORD dwAddr); extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr); // Serial.c +extern BOOL CommIsOpen(VOID); extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort); extern VOID CommClose(VOID); extern VOID CommSetBaud(VOID); diff --git a/Sources/Emu48/EMU48.RC b/Sources/Emu48/EMU48.RC index a2421ec..155416f 100644 --- a/Sources/Emu48/EMU48.RC +++ b/Sources/Emu48/EMU48.RC @@ -303,7 +303,7 @@ FONT 8, "MS Sans Serif" BEGIN ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP - LTEXT "Copyright © 2021 Christoph Gießelink && Sébastien Carlier", + LTEXT "Copyright © 2022 Christoph Gießelink && Sébastien Carlier", IDC_STATIC,29,18,181,8 DEFPUSHBUTTON "OK",IDOK,215,12,39,14 EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | @@ -723,8 +723,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,4,0 - PRODUCTVERSION 1,6,4,0 + FILEVERSION 1,6,5,0 + PRODUCTVERSION 1,6,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -741,12 +741,12 @@ BEGIN BEGIN VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 6, 4, 0\0" + VALUE "FileVersion", "1, 6, 5, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2021\0" + VALUE "LegalCopyright", "Copyright © 2022\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 6, 4, 0\0" + VALUE "ProductVersion", "1, 6, 5, 0\0" END END BLOCK "VarFileInfo" diff --git a/Sources/Emu48/EMU48.sln b/Sources/Emu48/EMU48.sln new file mode 100644 index 0000000..70dbd12 --- /dev/null +++ b/Sources/Emu48/EMU48.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32510.428 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Emu48", "Emu48.vcxproj", "{D259D821-B668-408E-B5DF-F0C7B42E6726}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|x86 = Debug Unicode|x86 + Debug|x86 = Debug|x86 + Release Unicode|x86 = Release Unicode|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Debug Unicode|x86.ActiveCfg = Debug Unicode|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Debug Unicode|x86.Build.0 = Debug Unicode|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Debug|x86.ActiveCfg = Debug|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Debug|x86.Build.0 = Debug|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Release Unicode|x86.ActiveCfg = Release Unicode|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Release Unicode|x86.Build.0 = Release Unicode|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Release|x86.ActiveCfg = Release|Win32 + {D259D821-B668-408E-B5DF-F0C7B42E6726}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0BE3DD55-AA0C-4A3D-87C1-C263EDE9BD89} + EndGlobalSection +EndGlobal diff --git a/Sources/Emu48/ENGINE.C b/Sources/Emu48/ENGINE.C index 785b7ac..e69f3ec 100644 --- a/Sources/Emu48/ENGINE.C +++ b/Sources/Emu48/ENGINE.C @@ -22,7 +22,6 @@ BOOL bRealSpeed = FALSE; BOOL bKeySlow = FALSE; // slow down for key emulation BOOL bSoundSlow = FALSE; // slow down for sound emulation UINT nOpcSlow = 0; // no. of opcodes to slow down -BOOL bCommInit = FALSE; // COM port not open CHIPSET Chipset; @@ -323,16 +322,15 @@ static __inline VOID AdjustSpeed(VOID) // adjust emulation speed VOID CheckSerial(VOID) { // COM port closed and serial on - if (bCommInit == FALSE && (Chipset.IORam[IOC] & SON) != 0) + if (CommIsOpen() == FALSE && (Chipset.IORam[IOC] & SON) != 0) { - bCommInit = CommOpen(szSerialWire,szSerialIr); // open COM ports + CommOpen(szSerialWire,szSerialIr); // open COM ports } // COM port opened and serial off - if (bCommInit == TRUE && (Chipset.IORam[IOC] & SON) == 0) + if (CommIsOpen() == TRUE && (Chipset.IORam[IOC] & SON) == 0) { CommClose(); // close COM port - bCommInit = FALSE; } return; } @@ -521,7 +519,6 @@ loop: { OnToolMacroStop(); // close open keyboard macro handler CommClose(); // close COM port - bCommInit = FALSE; // COM port not open nState = SM_INVALID; // in invalid state WaitForSingleObject(hEventShutdn,INFINITE); if (nNextState == SM_RETURN) // go into return state diff --git a/Sources/Emu48/EXTERNAL.C b/Sources/Emu48/EXTERNAL.C deleted file mode 100644 index c7864db..0000000 --- a/Sources/Emu48/EXTERNAL.C +++ /dev/null @@ -1,99 +0,0 @@ -/* - * external.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * Copyright (C) 2005 Christoph Gießelink - * - */ -#include "pch.h" -#include "Emu48.h" -#include "ops.h" - -//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name -//#F0E4F #80F0F #80F0F #706D2 #80850 #80F0F =SFLAG53_56 - -// memory address for flags -53 to -56 -#define SFLAG53_56 ( (cCurrentRomType=='6') \ - ? 0xE0E4F \ - : ( (cCurrentRomType=='A') \ - ? 0xF0E4F \ - : ( (cCurrentRomType!='E' && cCurrentRomType!='X') \ - ? ( (cCurrentRomType=='S') \ - ? 0x706D2 \ - : 0x80850 \ - ) \ - : 0x80F0F \ - ) \ - ) \ - ) - -VOID External(CHIPSET* w) // Beep patch -{ - BYTE fbeep; - DWORD freq,dur; - - freq = Npack(w->D,5); // frequency in Hz - dur = Npack(w->C,5); // duration in ms - Nread(&fbeep,SFLAG53_56,1); // fetch system flags -53 to -56 - - w->carry = TRUE; // setting of no beep - if (!(fbeep & 0x8) && freq) // bit -56 clear and frequency > 0 Hz - { - if (freq > 4400) freq = 4400; // high limit of HP (SX) - - SoundBeep(freq,dur); // beeping - - // estimate cpu cycles for beeping time (2MHz / 4MHz) - w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000); - - // original routine return with... - w->P = 0; // P=0 - w->intk = TRUE; // INTON - w->carry = FALSE; // RTNCC - } - w->pc = rstkpop(); - return; -} - -VOID RCKBp(CHIPSET* w) // ROM Check Beep patch -{ - DWORD dw2F,dwCpuFreq; - DWORD freq,dur; - BYTE f,d; - - f = w->C[1]; // f = freq ctl - d = w->C[0]; // d = duration ctl - - if (cCurrentRomType == 'S') // Clarke chip with 48S ROM - { - // CPU strobe frequency @ RATE 14 = 1.97MHz - dwCpuFreq = ((14 + 1) * 524288) >> 2; - - dw2F = f * 126 + 262; // F=f*63+131 - } - else // York chip with 48G and later ROM - { - // CPU strobe frequency @ RATE 27 = 3.67MHz - // CPU strobe frequency @ RATE 29 = 3.93MHz - dwCpuFreq = ((27 + 1) * 524288) >> 2; - - dw2F = f * 180 + 367; // F=f*90+183.5 - } - - freq = dwCpuFreq / dw2F; - dur = (dw2F * (256 - 16 * d)) * 1000 / 2 / dwCpuFreq; - - if (freq > 4400) freq = 4400; // high limit of HP - - SoundBeep(freq,dur); // beeping - - // estimate cpu cycles for beeping time (2MHz / 4MHz) - w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000); - - w->P = 0; // P=0 - w->carry = FALSE; // RTNCC - w->pc = rstkpop(); - return; -} diff --git a/Sources/Emu48/Emu48.vcxproj b/Sources/Emu48/Emu48.vcxproj new file mode 100644 index 0000000..b277133 --- /dev/null +++ b/Sources/Emu48/Emu48.vcxproj @@ -0,0 +1,352 @@ + + + + + Debug Unicode + Win32 + + + Debug + Win32 + + + Release Unicode + Win32 + + + Release + Win32 + + + + + + {D259D821-B668-408E-B5DF-F0C7B42E6726} + 10.0 + + + + Application + v142 + false + Unicode + + + Application + v142 + false + Unicode + + + Application + v142 + false + + + Application + v142 + false + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + NDEBUG;WIN32;_WINDOWS;STRICT;REGISTRY;%(PreprocessorDefinitions) + $(IntDir) + $(OutDir)$(TargetName).pch + Use + pch.h + $(IntDir) + $(IntDir) + FastCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\Emu48.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + $(IntDir)$(TargetName).bsc + + + true + Windows + $(IntDir)$(TargetName).exe + winmm.lib;comctl32.lib;ws2_32.lib;notelemetry.obj;%(AdditionalDependencies) + false + + + $(IntDir)$(TargetName)$(TargetExt).embed.manifest + + + $(IntDir)$(TargetName)$(TargetExt).embed.manifest.res + + + + + MultiThreadedDebug + Default + true + Disabled + true + Level3 + false + EditAndContinue + _DEBUG;WIN32;_WINDOWS;STRICT;REGISTRY;%(PreprocessorDefinitions) + $(IntDir) + true + $(OutDir)$(TargetName).pch + Use + pch.h + $(IntDir) + $(IntDir) + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\Emu48.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + $(IntDir)$(TargetName).bsc + + + true + true + Windows + $(IntDir)$(TargetName).exe + winmm.lib;comctl32.lib;ws2_32.lib;notelemetry.obj;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Default + true + Disabled + true + Level3 + false + EditAndContinue + _DEBUG;UNICODE;WIN32;_WINDOWS;STRICT;REGISTRY;%(PreprocessorDefinitions) + $(IntDir) + true + $(OutDir)$(TargetName).pch + Use + pch.h + $(IntDir) + $(IntDir) + + + true + _DEBUG;%(PreprocessorDefinitions) + .\DebugUnicode\Emu48.tlb + true + Win32 + + + 0x0409 + false + _DEBUG;%(PreprocessorDefinitions) + + + true + $(IntDir)$(TargetName).bsc + + + true + true + Windows + $(IntDir)$(TargetName).exe + winmm.lib;comctl32.lib;ws2_32.lib;notelemetry.obj;%(AdditionalDependencies) + false + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + NDEBUG;UNICODE;WIN32;_WINDOWS;STRICT;REGISTRY;%(PreprocessorDefinitions) + $(IntDir) + $(OutDir)$(TargetName).pch + Use + pch.h + $(IntDir) + $(IntDir) + FastCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\ReleaseUnicode\Emu48.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + $(IntDir)$(TargetName).bsc + + + true + Windows + $(IntDir)$(TargetName).exe + winmm.lib;comctl32.lib;ws2_32.lib;notelemetry.obj;%(AdditionalDependencies) + false + + + $(IntDir)$(TargetName)$(TargetExt).embed.manifest + + + $(IntDir)$(TargetName)$(TargetExt).embed.manifest.res + + + + + + + + + + + + + + + + + + + + LODEPNG_NO_COMPILE_ENCODER;LODEPNG_NO_COMPILE_DISK;LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS;LODEPNG_NO_COMPILE_ERROR_TEXT;LODEPNG_NO_COMPILE_CPP;%(PreprocessorDefinitions) + + + LODEPNG_NO_COMPILE_ENCODER;LODEPNG_NO_COMPILE_DISK;LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS;LODEPNG_NO_COMPILE_ERROR_TEXT;LODEPNG_NO_COMPILE_CPP;%(PreprocessorDefinitions) + + + LODEPNG_NO_COMPILE_ENCODER;LODEPNG_NO_COMPILE_DISK;LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS;LODEPNG_NO_COMPILE_ERROR_TEXT;LODEPNG_NO_COMPILE_CPP;%(PreprocessorDefinitions) + + + LODEPNG_NO_COMPILE_ENCODER;LODEPNG_NO_COMPILE_DISK;LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS;LODEPNG_NO_COMPILE_ERROR_TEXT;LODEPNG_NO_COMPILE_CPP;%(PreprocessorDefinitions) + + + + + + + + + Create + pch.h + Create + pch.h + Create + pch.h + Create + pch.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/Emu48/Emu48.vcxproj.filters b/Sources/Emu48/Emu48.vcxproj.filters new file mode 100644 index 0000000..0d598ae --- /dev/null +++ b/Sources/Emu48/Emu48.vcxproj.filters @@ -0,0 +1,169 @@ + + + + + {9bde1fa8-4321-4349-a509-2f450bb5c899} + cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 + + + {8a48e8bf-eaa3-44bf-8221-8e64ed0133a4} + h;hpp;hxx;hm;inl;fi;fd + + + {e37527a7-499d-4439-9ce5-858b55e7ac09} + ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/Sources/Emu48/Emu48.vcxproj.user b/Sources/Emu48/Emu48.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/Sources/Emu48/Emu48.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Sources/Emu48/FILES.C b/Sources/Emu48/FILES.C index d66e9d1..bee26d6 100644 --- a/Sources/Emu48/FILES.C +++ b/Sources/Emu48/FILES.C @@ -1721,7 +1721,7 @@ typedef struct _BmpFile LPBYTE pbyFile; // buffer } BMPFILE, FAR *LPBMPFILE, *PBMPFILE; -static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi) +static __inline WORD DibNumColors(__unaligned BITMAPINFOHEADER CONST *lpbi) { if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed; @@ -1729,7 +1729,7 @@ static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi) return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0; } -static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) +static HPALETTE CreateBIPalette(__unaligned BITMAPINFOHEADER CONST *lpbi) { LOGPALETTE* pPal; HPALETTE hpal = NULL; @@ -1738,12 +1738,9 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) BYTE green; BYTE blue; UINT i; - RGBQUAD* pRgb; + __unaligned RGBQUAD* pRgb; - if (!lpbi) - return NULL; - - if (lpbi->biSize != sizeof(BITMAPINFOHEADER)) + if (!lpbi || lpbi->biSize != sizeof(BITMAPINFOHEADER)) return NULL; // Get a pointer to the color table and the number of colors in it @@ -1807,22 +1804,19 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette) { - LPBITMAPFILEHEADER pBmfh; - LPBITMAPINFO pBmi; - HBITMAP hBitmap; - DWORD dwFileSize; + DWORD dwFileSize; - hBitmap = NULL; + HBITMAP hBitmap = NULL; - // size of bitmap header information + // map memory to BITMAPFILEHEADER and BITMAPINFO + const LPBITMAPFILEHEADER pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile; + const __unaligned LPBITMAPINFO pBmi = (__unaligned LPBITMAPINFO) & pBmfh[1]; + + // size of bitmap header information & check for bitmap dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - if (pBmp->dwFileSize < dwFileSize) return NULL; - - // check for bitmap - pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile; - if (pBmfh->bfType != 0x4D42) return NULL; // "BM" - - pBmi = (LPBITMAPINFO) (pBmp->pbyFile + sizeof(BITMAPFILEHEADER)); + if ( pBmp->dwFileSize < dwFileSize // minimum size to read data from BITMAPFILEHEADER + BITMAPINFOHEADER + || pBmfh->bfType != 0x4D42) // "BM" + return NULL; // size with color table if (pBmi->bmiHeader.biCompression == BI_BITFIELDS) @@ -2443,11 +2437,15 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette) if (hBitmap == NULL) goto quit; pbySrc = pbyImage; // init source loop pointer + pbyPixels += bmi.bmiHeader.biSizeImage; // end of destination bitmap // fill bottom up DIB pixel buffer with color information - for (nHeight = bmi.bmiHeader.biHeight - 1; nHeight >= 0; --nHeight) + for (nHeight = 0; nHeight < bmi.bmiHeader.biHeight; ++nHeight) { - LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine; + LPBYTE pbyLine; + + pbyPixels -= lBytesPerLine; // begin of previous row + pbyLine = pbyPixels; // row working copy for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth) { @@ -2456,8 +2454,6 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette) *pbyLine++ = pbySrc[0]; // red pbySrc += 3; } - - _ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage); } if (bPalette && hPalette == NULL) @@ -2473,12 +2469,6 @@ quit: { free(pbyImage); // free PNG image data } - - if (hBitmap != NULL && uError != 0) // creation failed - { - DeleteObject(hBitmap); // delete bitmap - hBitmap = NULL; - } return hBitmap; } diff --git a/Sources/Emu48/LODEPNG.C b/Sources/Emu48/LODEPNG.C index 532a21c..9d82e29 100644 --- a/Sources/Emu48/LODEPNG.C +++ b/Sources/Emu48/LODEPNG.C @@ -1,7 +1,7 @@ /* -LodePNG version 20210627 +LodePNG version 20220717 -Copyright (c) 2005-2021 Lode Vandevenne +Copyright (c) 2005-2022 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -44,10 +44,10 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20210627"; +const char* LODEPNG_VERSION_STRING = "20220717"; /* -This source file is built up in the following large parts. The code sections +This source file is divided into the following large parts. The code sections with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. -Tools for C and common code for PNG and Zlib -C Code for Zlib (huffman, deflate, ...) @@ -267,7 +267,7 @@ typedef struct ucvector { } ucvector; /*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned ucvector_resize(ucvector* p, size_t size) { +static unsigned ucvector_reserve(ucvector* p, size_t size) { if(size > p->allocsize) { size_t newsize = size + (p->allocsize >> 1u); void* data = lodepng_realloc(p->data, newsize); @@ -277,10 +277,15 @@ static unsigned ucvector_resize(ucvector* p, size_t size) { } else return 0; /*error: not enough memory*/ } - p->size = size; return 1; /*success*/ } +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) { + p->size = size; + return ucvector_reserve(p, size); +} + static ucvector ucvector_init(unsigned char* buffer, size_t size) { ucvector v; v.data = buffer; @@ -480,71 +485,62 @@ static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned c ensureBits functions: Ensures the reader can at least read nbits bits in one or more readBits calls, safely even if not enough bits are available. -Returns 1 if there are enough bits available, 0 if not. +The nbits parameter is unused but is given for documentation purposes, error +checking for amount of bits must be done beforehand. */ -/*See ensureBits documentation above. This one ensures exactly 1 bit */ -/*static unsigned ensureBits1(LodePNGBitReader* reader) { - if(reader->bp >= reader->bitsize) return 0; - reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u); - return 1; -}*/ - /*See ensureBits documentation above. This one ensures up to 9 bits */ -static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE void ensureBits9(LodePNGBitReader* reader, size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; if(start + 1u < size) { reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u); reader->buffer >>= (reader->bp & 7u); - return 1; } else { reader->buffer = 0; - if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 0u < size) reader->buffer = reader->data[start + 0]; reader->buffer >>= (reader->bp & 7u); - return reader->bp + nbits <= reader->bitsize; } + (void)nbits; } /*See ensureBits documentation above. This one ensures up to 17 bits */ -static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE void ensureBits17(LodePNGBitReader* reader, size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; if(start + 2u < size) { reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | ((unsigned)reader->data[start + 2] << 16u); reader->buffer >>= (reader->bp & 7u); - return 1; } else { reader->buffer = 0; if(start + 0u < size) reader->buffer |= reader->data[start + 0]; if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); reader->buffer >>= (reader->bp & 7u); - return reader->bp + nbits <= reader->bitsize; } + (void)nbits; } /*See ensureBits documentation above. This one ensures up to 25 bits */ -static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE void ensureBits25(LodePNGBitReader* reader, size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; if(start + 3u < size) { reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); reader->buffer >>= (reader->bp & 7u); - return 1; } else { reader->buffer = 0; if(start + 0u < size) reader->buffer |= reader->data[start + 0]; if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); reader->buffer >>= (reader->bp & 7u); - return reader->bp + nbits <= reader->bitsize; } + (void)nbits; } /*See ensureBits documentation above. This one ensures up to 32 bits */ -static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE void ensureBits32(LodePNGBitReader* reader, size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; if(start + 4u < size) { @@ -552,7 +548,6 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); reader->buffer >>= (reader->bp & 7u); reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u))); - return 1; } else { reader->buffer = 0; if(start + 0u < size) reader->buffer |= reader->data[start + 0]; @@ -560,48 +555,28 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u); reader->buffer >>= (reader->bp & 7u); - return reader->bp + nbits <= reader->bitsize; } + (void)nbits; } /* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */ -static unsigned peekBits(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE unsigned peekBits(LodePNGBitReader* reader, size_t nbits) { /* The shift allows nbits to be only up to 31. */ return reader->buffer & ((1u << nbits) - 1u); } /* Must have enough bits available with ensureBits */ -static void advanceBits(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE void advanceBits(LodePNGBitReader* reader, size_t nbits) { reader->buffer >>= nbits; reader->bp += nbits; } /* Must have enough bits available with ensureBits */ -static unsigned readBits(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE unsigned readBits(LodePNGBitReader* reader, size_t nbits) { unsigned result = peekBits(reader, nbits); advanceBits(reader, nbits); return result; } - -/* Public for testing only. steps and result must have numsteps values. */ -unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, - size_t numsteps, const size_t* steps, unsigned* result) { - size_t i; - LodePNGBitReader reader; - unsigned error = LodePNGBitReader_init(&reader, data, size); - if(error) return 0; - for(i = 0; i < numsteps; i++) { - size_t step = steps[i]; - unsigned ok; - if(step > 25) ok = ensureBits32(&reader, step); - else if(step > 17) ok = ensureBits25(&reader, step); - else if(step > 9) ok = ensureBits17(&reader, step); - else ok = ensureBits9(&reader, step); - if(!ok) return 0; - result[i] = readBits(&reader, step); - } - return 1; -} #endif /*LODEPNG_COMPILE_DECODER*/ static unsigned reverseBits(unsigned bits, unsigned num) { @@ -736,10 +711,11 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { numpresent = 0; for(i = 0; i < tree->numcodes; ++i) { unsigned l = tree->lengths[i]; - unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/ - /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/ - unsigned reverse = reverseBits(symbol, l); + unsigned symbol, reverse; if(l == 0) continue; + symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/ + /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/ + reverse = reverseBits(symbol, l); numpresent++; if(l <= FIRSTBITS) { @@ -1103,11 +1079,10 @@ static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* advanceBits(reader, l); return value; } else { - unsigned index2; advanceBits(reader, FIRSTBITS); - index2 = value + peekBits(reader, l - FIRSTBITS); - advanceBits(reader, codetree->table_len[index2] - FIRSTBITS); - return codetree->table_value[index2]; + value += peekBits(reader, l - FIRSTBITS); + advanceBits(reader, codetree->table_len[value] - FIRSTBITS); + return codetree->table_value[value]; } } #endif /*LODEPNG_COMPILE_DECODER*/ @@ -1140,7 +1115,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, unsigned* bitlen_cl = 0; HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ - if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/ + if(reader->bitsize - reader->bp < 14) return 49; /*error: the bit pointer is or will go past the memory*/ + ensureBits17(reader, 14); /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ HLIT = readBits(reader, 5) + 257; @@ -1265,6 +1241,10 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, unsigned error = 0; HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ HuffmanTree tree_d; /*the huffman tree for distance codes*/ + const size_t reserved_size = 260; /* must be at least 258 for max length, and a few extra for adding a few extra literals */ + int done = 0; + + if(!ucvector_reserve(out, out->size + reserved_size)) return 83; /*alloc fail*/ HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); @@ -1272,14 +1252,21 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d); else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader); - while(!error) /*decode all symbols until end reached, breaks at end code*/ { + + while(!error && !done) /*decode all symbols until end reached, breaks at end code*/ { /*code_ll is literal, length or end code*/ unsigned code_ll; - ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */ + /* ensure enough bits for 2 huffman code reads (15 bits each): if the first is a literal, a second literal is read at once. This + appears to be slightly faster, than ensuring 20 bits here for 1 huffman symbol and the potential 5 extra bits for the length symbol.*/ + ensureBits32(reader, 30); code_ll = huffmanDecodeSymbol(reader, &tree_ll); + if(code_ll <= 255) { + /*slightly faster code path if multiple literals in a row*/ + out->data[out->size++] = (unsigned char)code_ll; + code_ll = huffmanDecodeSymbol(reader, &tree_ll); + } if(code_ll <= 255) /*literal symbol*/ { - if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/); - out->data[out->size - 1] = (unsigned char)code_ll; + out->data[out->size++] = (unsigned char)code_ll; } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { unsigned code_d, distance; unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ @@ -1292,6 +1279,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; if(numextrabits_l != 0) { /* bits already ensured above */ + ensureBits25(reader, 5); length += readBits(reader, numextrabits_l); } @@ -1319,7 +1307,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ backward = start - distance; - if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/); + out->size += length; if(distance < length) { size_t forward; lodepng_memcpy(out->data + start, out->data + backward, distance); @@ -1331,10 +1319,13 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, lodepng_memcpy(out->data + start, out->data + backward, length); } } else if(code_ll == 256) { - break; /*end code, break the loop*/ + done = 1; /*end code, finish the loop*/ } else /*if(code_ll == INVALIDSYMBOL)*/ { ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ } + if(out->allocsize - out->size < reserved_size) { + if(!ucvector_reserve(out, out->size + reserved_size)) ERROR_BREAK(83); /*alloc fail*/ + } /*check if any of the ensureBits above went out of bounds*/ if(reader->bp > reader->bitsize) { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol @@ -1377,8 +1368,11 @@ static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, /*read the literal data: LEN bytes are now stored in the out buffer*/ if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/ - lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN); - bytepos += LEN; + /*out->data can be NULL (when LEN is zero), and arithmetics on NULL ptr is undefined*/ + if (LEN) { + lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN); + bytepos += LEN; + } reader->bp = bytepos << 3u; @@ -1396,7 +1390,8 @@ static unsigned lodepng_inflatev(ucvector* out, while(!BFINAL) { unsigned BTYPE; - if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/ + if(reader.bitsize - reader.bp < 3) return 52; /*error, bit pointer will jump past memory*/ + ensureBits9(&reader, 3); BFINAL = readBits(&reader, 1); BTYPE = readBits(&reader, 2); @@ -2378,7 +2373,7 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, /* ////////////////////////////////////////////////////////////////////////// */ -#ifndef LODEPNG_NO_COMPILE_CRC +#ifdef LODEPNG_COMPILE_CRC /* CRC polynomial: 0xedb88320 */ static unsigned lodepng_crc32_table[256] = { 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, @@ -2424,9 +2419,11 @@ unsigned lodepng_crc32(const unsigned char* data, size_t length) { } return r ^ 0xffffffffu; } -#else /* !LODEPNG_NO_COMPILE_CRC */ +#else /* LODEPNG_COMPILE_CRC */ +/*in this case, the function is only declared here, and must be defined externally +so that it will be linked in*/ unsigned lodepng_crc32(const unsigned char* data, size_t length); -#endif /* !LODEPNG_NO_COMPILE_CRC */ +#endif /* LODEPNG_COMPILE_CRC */ /* ////////////////////////////////////////////////////////////////////////// */ /* / Reading and writing PNG color channel bits / */ @@ -2464,7 +2461,7 @@ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, /* ////////////////////////////////////////////////////////////////////////// */ unsigned lodepng_chunk_length(const unsigned char* chunk) { - return lodepng_read32bitInt(&chunk[0]); + return lodepng_read32bitInt(chunk); } void lodepng_chunk_type(char type[5], const unsigned char* chunk) { @@ -2514,34 +2511,32 @@ void lodepng_chunk_generate_crc(unsigned char* chunk) { } unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) { - if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/ + size_t available_size = (size_t)(end - chunk); + if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/ if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ return chunk + 8; } else { size_t total_chunk_length; - unsigned char* result; if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; - result = chunk + total_chunk_length; - if(result < chunk) return end; /*pointer overflow*/ - return result; + if(total_chunk_length > available_size) return end; /*outside of range*/ + return chunk + total_chunk_length; } } const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) { - if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/ + size_t available_size = (size_t)(end - chunk); + if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/ if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ return chunk + 8; } else { size_t total_chunk_length; - const unsigned char* result; if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; - result = chunk + total_chunk_length; - if(result < chunk) return end; /*pointer overflow*/ - return result; + if(total_chunk_length > available_size) return end; /*outside of range*/ + return chunk + total_chunk_length; } } @@ -2586,7 +2581,7 @@ the data is at chunk + 8. To finalize chunk, add the data, then use lodepng_chunk_generate_crc */ static unsigned lodepng_chunk_init(unsigned char** chunk, ucvector* out, - unsigned length, const char* type) { + size_t length, const char* type) { size_t new_length = out->size; if(lodepng_addofl(new_length, length, &new_length)) return 77; if(lodepng_addofl(new_length, 12, &new_length)) return 77; @@ -2594,7 +2589,7 @@ static unsigned lodepng_chunk_init(unsigned char** chunk, *chunk = out->data + new_length - length - 12u; /*1: length*/ - lodepng_set32bitInt(*chunk, length); + lodepng_set32bitInt(*chunk, (unsigned)length); /*2: chunk name (4 letters)*/ lodepng_memcpy(*chunk + 4, type, 4); @@ -2604,7 +2599,7 @@ static unsigned lodepng_chunk_init(unsigned char** chunk, /* like lodepng_chunk_create but with custom allocsize */ static unsigned lodepng_chunk_createv(ucvector* out, - unsigned length, const char* type, const unsigned char* data) { + size_t length, const char* type, const unsigned char* data) { unsigned char* chunk; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type)); @@ -3051,6 +3046,9 @@ void lodepng_info_init(LodePNGInfo* info) { info->iccp_name = NULL; info->iccp_profile = NULL; + info->sbit_defined = 0; + info->sbit_r = info->sbit_g = info->sbit_b = info->sbit_a = 0; + LodePNGUnknownChunks_init(info); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } @@ -3945,7 +3943,7 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out, if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize && mode_in->bitdepth == mode_out->bitdepth) { /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ - lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_cleanup(mode_out); /*clears palette, keeps the above set colortype and bitdepth fields as-is*/ lodepng_color_mode_copy(mode_out, mode_in); } } else /*8-bit or 16-bit per channel*/ { @@ -4135,10 +4133,9 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan too much code. Whether this speeds up anything depends on compiler and settings. */ if(bytewidth >= 4) { for(; i + 3 < length; i += 4, j += 4) { - unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0]; - unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1]; - unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2]; - unsigned char s3 = scanline[i + 3], r3 = recon[j + 3], p3 = precon[i + 3]; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3]; recon[i + 0] = s0 + ((r0 + p0) >> 1u); recon[i + 1] = s1 + ((r1 + p1) >> 1u); recon[i + 2] = s2 + ((r2 + p2) >> 1u); @@ -4146,17 +4143,18 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan } } else if(bytewidth >= 3) { for(; i + 2 < length; i += 3, j += 3) { - unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0]; - unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1]; - unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2]; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2]; recon[i + 0] = s0 + ((r0 + p0) >> 1u); recon[i + 1] = s1 + ((r1 + p1) >> 1u); recon[i + 2] = s2 + ((r2 + p2) >> 1u); } } else if(bytewidth >= 2) { for(; i + 1 < length; i += 2, j += 2) { - unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0]; - unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1]; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1]; recon[i + 0] = s0 + ((r0 + p0) >> 1u); recon[i + 1] = s1 + ((r1 + p1) >> 1u); } @@ -4732,6 +4730,47 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/ return error; } + +/*significant bits chunk (sBIT)*/ +static unsigned readChunk_sBIT(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth; + if(info->color.colortype == LCT_GREY) { + /*error: this chunk must be 1 bytes for grayscale image*/ + if(chunkLength != 1) return 114; + if(data[0] == 0 || data[0] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/ + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) { + /*error: this chunk must be 3 bytes for RGB and palette image*/ + if(chunkLength != 3) return 114; + if(data[0] == 0 || data[1] == 0 || data[2] == 0) return 115; + if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = data[0]; + info->sbit_g = data[1]; + info->sbit_b = data[2]; + } else if(info->color.colortype == LCT_GREY_ALPHA) { + /*error: this chunk must be 2 byte for grayscale with alpha image*/ + if(chunkLength != 2) return 114; + if(data[0] == 0 || data[1] == 0) return 115; + if(data[0] > bitdepth || data[1] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/ + info->sbit_a = data[1]; + } else if(info->color.colortype == LCT_RGBA) { + /*error: this chunk must be 4 bytes for grayscale image*/ + if(chunkLength != 4) return 114; + if(data[0] == 0 || data[1] == 0 || data[2] == 0 || data[3] == 0) return 115; + if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth || data[3] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = data[0]; + info->sbit_g = data[1]; + info->sbit_b = data[2]; + info->sbit_a = data[3]; + } + + return 0; /* OK */ +} #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, @@ -4746,7 +4785,7 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, chunkLength = lodepng_chunk_length(chunk); if(chunkLength > 2147483647) return 63; data = lodepng_chunk_data_const(chunk); - if(data + chunkLength + 4 > in + insize) return 30; + if(chunkLength + 12 > insize - pos) return 30; if(lodepng_chunk_type_equals(chunk, "PLTE")) { error = readChunk_PLTE(&state->info_png.color, data, chunkLength); @@ -4773,6 +4812,8 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, error = readChunk_sRGB(&state->info_png, data, chunkLength); } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "sBIT")) { + error = readChunk_sBIT(&state->info_png, data, chunkLength); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } else { /* unhandled chunk is ok (is not an error) */ @@ -4791,7 +4832,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize) { unsigned char IEND = 0; - const unsigned char* chunk; + const unsigned char* chunk; /*points to beginning of next chunk*/ unsigned char* idat; /*the data from idat chunks, zlib compressed*/ size_t idatsize = 0; unsigned char* scanlines = 0; @@ -4827,14 +4868,15 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, while(!IEND && !state->error) { unsigned chunkLength; const unsigned char* data; /*the data in the chunk*/ + size_t pos = (size_t)(chunk - in); - /*error: size of the in buffer too small to contain next chunk*/ - if((size_t)((chunk - in) + 12) > insize || chunk < in) { + /*error: next chunk out of bounds of the in buffer*/ + if(chunk < in || pos + 12 > insize) { if(state->decoder.ignore_end) break; /*other errors may still happen though*/ CERROR_BREAK(state->error, 30); } - /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + /*length of the data of the chunk, excluding the 12 bytes for length, chunk type and CRC*/ chunkLength = lodepng_chunk_length(chunk); /*error: chunk length larger than the max PNG chunk size*/ if(chunkLength > 2147483647) { @@ -4842,8 +4884,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, CERROR_BREAK(state->error, 63); } - if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) { - CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + if(pos + (size_t)chunkLength + 12 > insize || pos + (size_t)chunkLength + 12 < pos) { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk (or int overflow)*/ } data = lodepng_chunk_data_const(chunk); @@ -4917,6 +4959,9 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "sBIT")) { + state->error = readChunk_sBIT(&state->info_png, data, chunkLength); + if(state->error) break; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ @@ -5152,7 +5197,11 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { unsigned char* chunk; size_t i, j = 8; - CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)info->palettesize * 3, "PLTE")); + if(info->palettesize == 0 || info->palettesize > 256) { + return 68; /*invalid palette size, it is only allowed to be 1-256*/ + } + + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE")); for(i = 0; i != info->palettesize; ++i) { /*add all channels except alpha channel*/ @@ -5176,7 +5225,7 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { --amount; } if(amount) { - CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)amount, "tRNS")); + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS")); /*add the alpha channel values from the palette*/ for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3]; } @@ -5210,7 +5259,7 @@ static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t d error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings); if(!error) { - error = lodepng_chunk_createv(out, (unsigned)zlibsize, "IDAT", zlib); + error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib); } lodepng_free(zlib); return error; @@ -5227,7 +5276,7 @@ static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* te size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring); size_t size = keysize + 1 + textsize; if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ - CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)size, "tEXt")); + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt")); lodepng_memcpy(chunk + 8, keyword, keysize); chunk[8 + keysize] = 0; /*null termination char*/ lodepng_memcpy(chunk + 9 + keysize, textstring, textsize); @@ -5249,7 +5298,7 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te (const unsigned char*)textstring, textsize, zlibsettings); if(!error) { size_t size = keysize + 2 + compressedsize; - error = lodepng_chunk_init(&chunk, out, (unsigned)size, "zTXt"); + error = lodepng_chunk_init(&chunk, out, size, "zTXt"); } if(!error) { lodepng_memcpy(chunk + 8, keyword, keysize); @@ -5280,7 +5329,7 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyw } if(!error) { size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize); - error = lodepng_chunk_init(&chunk, out, (unsigned)size, "iTXt"); + error = lodepng_chunk_init(&chunk, out, size, "iTXt"); } if(!error) { size_t pos = 8; @@ -5393,7 +5442,7 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom info->iccp_profile, info->iccp_profile_size, zlibsettings); if(!error) { size_t size = keysize + 2 + compressedsize; - error = lodepng_chunk_init(&chunk, out, (unsigned)size, "iCCP"); + error = lodepng_chunk_init(&chunk, out, size, "iCCP"); } if(!error) { lodepng_memcpy(chunk + 8, info->iccp_name, keysize); @@ -5407,6 +5456,42 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom return error; } +static unsigned addChunk_sBIT(ucvector* out, const LodePNGInfo* info) { + unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth; + unsigned char* chunk = 0; + if(info->color.colortype == LCT_GREY) { + if(info->sbit_r == 0 || info->sbit_r > bitdepth) return 115; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "sBIT")); + chunk[8] = info->sbit_r; + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) { + if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0) return 115; + if(info->sbit_r > bitdepth || info->sbit_g > bitdepth || info->sbit_b > bitdepth) return 115; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 3, "sBIT")); + chunk[8] = info->sbit_r; + chunk[9] = info->sbit_g; + chunk[10] = info->sbit_b; + } else if(info->color.colortype == LCT_GREY_ALPHA) { + if(info->sbit_r == 0 || info->sbit_a == 0) return 115; + if(info->sbit_r > bitdepth || info->sbit_a > bitdepth) return 115; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "sBIT")); + chunk[8] = info->sbit_r; + chunk[9] = info->sbit_a; + } else if(info->color.colortype == LCT_RGBA) { + if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0 || info->sbit_a == 0 || + info->sbit_r > bitdepth || info->sbit_g > bitdepth || + info->sbit_b > bitdepth || info->sbit_a > bitdepth) { + return 115; + } + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "sBIT")); + chunk[8] = info->sbit_r; + chunk[9] = info->sbit_g; + chunk[10] = info->sbit_b; + chunk[11] = info->sbit_a; + } + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; +} + #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, @@ -5852,8 +5937,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, ucvector outv = ucvector_init(NULL, 0); LodePNGInfo info; const LodePNGInfo* info_png = &state->info_png; + LodePNGColorMode auto_color; lodepng_info_init(&info); + lodepng_color_mode_init(&auto_color); /*provide some proper output values if error will happen*/ *out = 0; @@ -5863,6 +5950,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, /*check input values validity*/ if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette) && (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) { + /*this error is returned even if auto_convert is enabled and thus encoder could + generate the palette by itself: while allowing this could be possible in theory, + it may complicate the code or edge cases, and always requiring to give a palette + when setting this color type is a simpler contract*/ state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ goto cleanup; } @@ -5883,6 +5974,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, lodepng_info_copy(&info, &state->info_png); if(state->encoder.auto_convert) { LodePNGColorStats stats; + unsigned allow_convert = 1; lodepng_color_stats_init(&stats); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS if(info_png->iccp_defined && @@ -5904,23 +5996,85 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, /*the background chunk's color must be taken into account as well*/ unsigned r = 0, g = 0, b = 0; LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16); - lodepng_convert_rgb(&r, &g, &b, info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color); + lodepng_convert_rgb(&r, &g, &b, + info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color); state->error = lodepng_color_stats_add(&stats, r, g, b, 65535); if(state->error) goto cleanup; } #endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ - state->error = auto_choose_color(&info.color, &state->info_raw, &stats); + state->error = auto_choose_color(&auto_color, &state->info_raw, &stats); if(state->error) goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /*also convert the background chunk*/ - if(info_png->background_defined) { - if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b, - info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) { - state->error = 104; - goto cleanup; + if(info_png->sbit_defined) { + /*if sbit is defined, due to strict requirements of which sbit values can be present for which color modes, + auto_convert can't be done in many cases. However, do support a few cases here. + TODO: more conversions may be possible, and it may also be possible to get a more appropriate color type out of + auto_choose_color if knowledge about sbit is used beforehand + */ + unsigned sbit_max = LODEPNG_MAX(LODEPNG_MAX(LODEPNG_MAX(info_png->sbit_r, info_png->sbit_g), + info_png->sbit_b), info_png->sbit_a); + unsigned equal = (!info_png->sbit_g || info_png->sbit_g == info_png->sbit_r) + && (!info_png->sbit_b || info_png->sbit_b == info_png->sbit_r) + && (!info_png->sbit_a || info_png->sbit_a == info_png->sbit_r); + allow_convert = 0; + if(info.color.colortype == LCT_PALETTE && + auto_color.colortype == LCT_PALETTE) { + /* input and output are palette, and in this case it may happen that palette data is + expected to be copied from info_raw into the info_png */ + allow_convert = 1; + } + /*going from 8-bit RGB to palette (or 16-bit as long as sbit_max <= 8) is possible + since both are 8-bit RGB for sBIT's purposes*/ + if(info.color.colortype == LCT_RGB && + auto_color.colortype == LCT_PALETTE && sbit_max <= 8) { + allow_convert = 1; + } + /*going from 8-bit RGBA to palette is also ok but only if sbit_a is exactly 8*/ + if(info.color.colortype == LCT_RGBA && auto_color.colortype == LCT_PALETTE && + info_png->sbit_a == 8 && sbit_max <= 8) { + allow_convert = 1; + } + /*going from 16-bit RGB(A) to 8-bit RGB(A) is ok if all sbit values are <= 8*/ + if((info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA) && info.color.bitdepth == 16 && + auto_color.colortype == info.color.colortype && auto_color.bitdepth == 8 && + sbit_max <= 8) { + allow_convert = 1; + } + /*going to less channels is ok if all bit values are equal (all possible values in sbit, + as well as the chosen bitdepth of the result). Due to how auto_convert works, + we already know that auto_color.colortype has less than or equal amount of channels than + info.colortype. Palette is not used here. This conversion is not allowed if + info_png->sbit_r < auto_color.bitdepth, because specifically for alpha, non-presence of + an sbit value heavily implies that alpha's bit depth is equal to the PNG bit depth (rather + than the bit depths set in the r, g and b sbit values, by how the PNG specification describes + handling tRNS chunk case with sBIT), so be conservative here about ignoring user input.*/ + if(info.color.colortype != LCT_PALETTE && auto_color.colortype != LCT_PALETTE && + equal && info_png->sbit_r == auto_color.bitdepth) { + allow_convert = 1; } } +#endif + if(state->encoder.force_palette) { + if(info.color.colortype != LCT_GREY && info.color.colortype != LCT_GREY_ALPHA && + (auto_color.colortype == LCT_GREY || auto_color.colortype == LCT_GREY_ALPHA)) { + /*user speficially forced a PLTE palette, so cannot convert to grayscale types because + the PNG specification only allows writing a suggested palette in PLTE for truecolor types*/ + allow_convert = 0; + } + } + if(allow_convert) { + lodepng_color_mode_copy(&info.color, &auto_color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*also convert the background chunk*/ + if(info_png->background_defined) { + if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b, + info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) { + state->error = 104; + goto cleanup; + } + } #endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + } } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS if(info_png->iccp_defined) { @@ -5991,6 +6145,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, state->error = addChunk_cHRM(&outv, &info); if(state->error) goto cleanup; } + if(info_png->sbit_defined) { + state->error = addChunk_sBIT(&outv, &info); + if(state->error) goto cleanup; + } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*PLTE*/ if(info.color.colortype == LCT_PALETTE) { @@ -6097,6 +6255,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, cleanup: lodepng_info_cleanup(&info); lodepng_free(data); + lodepng_color_mode_cleanup(&auto_color); /*instead of cleaning the vector up, give it to the output*/ *out = outv.data; @@ -6291,6 +6450,8 @@ const char* lodepng_error_text(unsigned code) { /*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents unreasonable memory consumption when decoding due to impossibly large ICC profile*/ case 113: return "ICC profile unreasonably large"; + case 114: return "sBIT chunk has wrong size for the color type of the image"; + case 115: return "sBIT value out of range"; } return "unknown error code"; } @@ -6327,7 +6488,7 @@ unsigned decompress(std::vector& out, const unsigned char* in, si size_t buffersize = 0; unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings); if(buffer) { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); + out.insert(out.end(), buffer, &buffer[buffersize]); lodepng_free(buffer); } return error; @@ -6346,7 +6507,7 @@ unsigned compress(std::vector& out, const unsigned char* in, size size_t buffersize = 0; unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); if(buffer) { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); + out.insert(out.end(), buffer, &buffer[buffersize]); lodepng_free(buffer); } return error; @@ -6391,7 +6552,7 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); - out.insert(out.end(), &buffer[0], &buffer[buffersize]); + out.insert(out.end(), buffer, &buffer[buffersize]); } lodepng_free(buffer); return error; @@ -6409,7 +6570,7 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); if(buffer && !error) { size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); - out.insert(out.end(), &buffer[0], &buffer[buffersize]); + out.insert(out.end(), buffer, &buffer[buffersize]); } lodepng_free(buffer); return error; @@ -6441,7 +6602,7 @@ unsigned encode(std::vector& out, const unsigned char* in, unsign size_t buffersize; unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); if(buffer) { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); + out.insert(out.end(), buffer, &buffer[buffersize]); lodepng_free(buffer); } return error; @@ -6461,7 +6622,7 @@ unsigned encode(std::vector& out, size_t buffersize; unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); if(buffer) { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); + out.insert(out.end(), buffer, &buffer[buffersize]); lodepng_free(buffer); } return error; diff --git a/Sources/Emu48/LODEPNG.H b/Sources/Emu48/LODEPNG.H index 3e1da92..fdafc77 100644 --- a/Sources/Emu48/LODEPNG.H +++ b/Sources/Emu48/LODEPNG.H @@ -1,7 +1,7 @@ /* -LodePNG version 20210627 +LodePNG version 20220717 -Copyright (c) 2005-2021 Lode Vandevenne +Copyright (c) 2005-2022 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -35,43 +35,50 @@ The following #defines are used to create code sections. They can be disabled to disable code sections, which can give faster compile time and smaller binary. The "NO_COMPILE" defines are designed to be used to pass as defines to the compiler command to disable them without modifying this header, e.g. --DLODEPNG_NO_COMPILE_ZLIB for gcc. -In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to -allow implementing a custom lodepng_crc32. +-DLODEPNG_NO_COMPILE_ZLIB for gcc or clang. */ /*deflate & zlib. If disabled, you must specify alternative zlib functions in the custom_zlib field of the compress and decompress settings*/ #ifndef LODEPNG_NO_COMPILE_ZLIB +/*pass -DLODEPNG_NO_COMPILE_ZLIB to the compiler to disable this, or comment out LODEPNG_COMPILE_ZLIB below*/ #define LODEPNG_COMPILE_ZLIB #endif /*png encoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_PNG +/*pass -DLODEPNG_NO_COMPILE_PNG to the compiler to disable this, or comment out LODEPNG_COMPILE_PNG below*/ #define LODEPNG_COMPILE_PNG #endif /*deflate&zlib decoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_DECODER +/*pass -DLODEPNG_NO_COMPILE_DECODER to the compiler to disable this, or comment out LODEPNG_COMPILE_DECODER below*/ #define LODEPNG_COMPILE_DECODER #endif /*deflate&zlib encoder and png encoder*/ #ifndef LODEPNG_NO_COMPILE_ENCODER +/*pass -DLODEPNG_NO_COMPILE_ENCODER to the compiler to disable this, or comment out LODEPNG_COMPILE_ENCODER below*/ #define LODEPNG_COMPILE_ENCODER #endif /*the optional built in harddisk file loading and saving functions*/ #ifndef LODEPNG_NO_COMPILE_DISK +/*pass -DLODEPNG_NO_COMPILE_DISK to the compiler to disable this, or comment out LODEPNG_COMPILE_DISK below*/ #define LODEPNG_COMPILE_DISK #endif /*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +/*pass -DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS to the compiler to disable this, +or comment out LODEPNG_COMPILE_ANCILLARY_CHUNKS below*/ #define LODEPNG_COMPILE_ANCILLARY_CHUNKS #endif /*ability to convert error numerical codes to English text string*/ #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +/*pass -DLODEPNG_NO_COMPILE_ERROR_TEXT to the compiler to disable this, +or comment out LODEPNG_COMPILE_ERROR_TEXT below*/ #define LODEPNG_COMPILE_ERROR_TEXT #endif @@ -79,12 +86,24 @@ the custom_zlib field of the compress and decompress settings*/ you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your source files with custom allocators.*/ #ifndef LODEPNG_NO_COMPILE_ALLOCATORS +/*pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler to disable the built-in ones, +or comment out LODEPNG_COMPILE_ALLOCATORS below*/ #define LODEPNG_COMPILE_ALLOCATORS #endif +/*Disable built-in CRC function, in that case a custom implementation of +lodepng_crc32 must be defined externally so that it can be linked in.*/ +#ifndef LODEPNG_NO_COMPILE_CRC +/*pass -DLODEPNG_NO_COMPILE_CRC to the compiler to disable the built-in one, +or comment out LODEPNG_COMPILE_CRC below*/ +#define LODEPNG_COMPILE_CRC +#endif + /*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ #ifdef __cplusplus #ifndef LODEPNG_NO_COMPILE_CPP +/*pass -DLODEPNG_NO_COMPILE_CPP to the compiler to disable C++ (not needed if a C-only compiler), +or comment out LODEPNG_COMPILE_CPP below*/ #define LODEPNG_COMPILE_CPP #endif #endif @@ -374,8 +393,10 @@ typedef struct LodePNGColorMode { The alpha channels must be set as well, set them to 255 for opaque images. - When decoding, by default you can ignore this palette, since LodePNG already - fills the palette colors in the pixels of the raw RGBA output. + When decoding, with the default settings you can ignore this palette, since + LodePNG already fills the palette colors in the pixels of the raw RGBA output, + but when decoding to the original PNG color mode it is needed to reconstruct + the colors. The palette is only supported for color type 3. */ @@ -465,10 +486,12 @@ typedef struct LodePNGInfo { with values truncated to the bit depth in the unsigned integer. For grayscale and palette PNGs, the value is stored in background_r. The values - in background_g and background_b are then unused. + in background_g and background_b are then unused. The decoder will set them + equal to background_r, the encoder ignores them in this case. - So when decoding, you may get these in a different color mode than the one you requested - for the raw pixels. + When decoding, you may get these in a different color mode than the one you requested + for the raw pixels: the colortype and bitdepth defined by info_png.color, that is the + ones defined in the header of the PNG image, are used. When encoding with auto_convert, you must use the color model defined in info_png.color for these values. The encoder normally ignores info_png.color when auto_convert is on, but will @@ -535,7 +558,7 @@ typedef struct LodePNGInfo { unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ /* - Color profile related chunks: gAMA, cHRM, sRGB, iCPP + Color profile related chunks: gAMA, cHRM, sRGB, iCPP, sBIT LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please @@ -598,6 +621,45 @@ typedef struct LodePNGInfo { unsigned char* iccp_profile; unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ + /* + sBIT chunk: significant bits. Optional metadata, only set this if needed. + + If defined, these values give the bit depth of the original data. Since PNG only stores 1, 2, 4, 8 or 16-bit + per channel data, the significant bits value can be used to indicate the original encoded data has another + sample depth, such as 10 or 12. + + Encoders using this value, when storing the pixel data, should use the most significant bits + of the data to store the original bits, and use a good sample depth scaling method such as + "left bit replication" to fill in the least significant bits, rather than fill zeroes. + + Decoders using this value, if able to work with data that's e.g. 10-bit or 12-bit, should right + shift the data to go back to the original bit depth, but decoders are also allowed to ignore + sbit and work e.g. with the 8-bit or 16-bit data from the PNG directly, since thanks + to the encoder contract, the values encoded in PNG are in valid range for the PNG bit depth. + + For grayscale images, sbit_g and sbit_b are not used, and for images that don't use color + type RGBA or grayscale+alpha, sbit_a is not used (it's not used even for palette images with + translucent palette values, or images with color key). The values that are used must be + greater than zero and smaller than or equal to the PNG bit depth. + + The color type from the header in the PNG image defines these used and unused fields: if + decoding with a color mode conversion, such as always decoding to RGBA, this metadata still + only uses the color type of the original PNG, and may e.g. lack the alpha channel info + if the PNG was RGB. When encoding with auto_convert (as well as without), also always the + color model defined in info_png.color determines this. + + NOTE: enabling sbit can hurt compression, because the encoder can then not always use + auto_convert to choose a more optimal color mode for the data, because the PNG format has + strict requirements for the allowed sbit values in combination with color modes. + For example, setting these fields to 10-bit will force the encoder to keep using a 16-bit per channel + color mode, even if the pixel data would in fact fit in a more efficient 8-bit mode. + */ + unsigned sbit_defined; /*is significant bits given? if not, the values below are unused*/ + unsigned sbit_r; /*red or gray component of significant bits*/ + unsigned sbit_g; /*green component of significant bits*/ + unsigned sbit_b; /*blue component of significant bits*/ + unsigned sbit_a; /*alpha component of significant bits*/ + /* End of color profile related chunks */ @@ -770,7 +832,11 @@ typedef struct LodePNGEncoderSettings { const unsigned char* predefined_filters; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). - If colortype is 3, PLTE is _always_ created.*/ + If colortype is 3, PLTE is always created. If color type is explicitely set + to a grayscale type (1 or 4), this is not done and is ignored. If enabling this, + a palette must be present in the info_png. + NOTE: enabling this may worsen compression if auto_convert is used to choose + optimal color mode, because it cannot use grayscale color modes in this case*/ unsigned force_palette; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*add LodePNG identifier and version as a text chunk, for debugging*/ @@ -824,8 +890,8 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h, #endif /*LODEPNG_COMPILE_DECODER*/ /* -Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it -read in the state. Returns error code on failure. +Reads one metadata chunk (other than IHDR, which is handled by lodepng_inspect) +of the PNG file and outputs what it read in the state. Returns error code on failure. Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const to find the desired chunk type, and if non null use lodepng_inspect_chunk (with chunk_pointer - start_of_file as pos). @@ -1103,7 +1169,7 @@ TODO: [.] check compatibility with various compilers - done but needs to be redone for every newer version [X] converting color to 16-bit per channel types [X] support color profile chunk types (but never let them touch RGB values by default) -[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST) +[ ] support all public PNG chunk types (almost done except sPLT and hIST) [ ] make sure encoder generates no chunks with size > (2^31)-1 [ ] partial decoding (stream processing) [X] let the "isFullyOpaque" function check color keys and transparent palettes too @@ -1230,18 +1296,16 @@ The following features are supported by the decoder: gAMA: RGB gamma correction iCCP: ICC color profile sRGB: rendering intent + sBIT: significant bits 1.2. features not supported --------------------------- -The following features are _not_ supported: +The following features are not (yet) supported: *) some features needed to make a conformant PNG-Editor might be still missing. *) partial loading/stream processing. All data must be available and is processed in one call. -*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG: - sBIT - hIST - sPLT +*) The hIST and sPLT public chunks are not (yet) supported but treated as unknown chunks 2. C and C++ version @@ -1845,6 +1909,8 @@ symbol. Not all changes are listed here, the commit history in github lists more: https://github.com/lvandeve/lodepng +*) 13 jun 2022: added support for the sBIT chunk. +*) 09 jan 2022: minor decoder speed improvements. *) 27 jun 2021: added warnings that file reading/writing functions don't support wide-character filenames (support for this is not planned, opening files is not the core part of PNG decoding/decoding and is platform dependent). @@ -2015,5 +2081,5 @@ Domain: gmail dot com. Account: lode dot vandevenne. -Copyright (c) 2005-2021 Lode Vandevenne +Copyright (c) 2005-2022 Lode Vandevenne */ diff --git a/Sources/Emu48/MOPS.C b/Sources/Emu48/MOPS.C index 9825ba3..ff6e96e 100644 --- a/Sources/Emu48/MOPS.C +++ b/Sources/Emu48/MOPS.C @@ -1140,8 +1140,11 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate) case 0x15: // RBR MSB if (bUpdate) { - Chipset.IORam[RCS] &= ~RBF; *a = Chipset.IORam[d]; // return RBR value + if (d==0x15) // reading RBR MSB + { + Chipset.IORam[RCS] &= ~RBF; // clear Receive Buffer Full flag + } UpdateUSRQ(); // update USRQ rbr_acc = TRUE; // search for new RBR value #if defined DEBUG_SERIAL @@ -1586,13 +1589,13 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only) // 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event case 0x1A: - // COM port open and EIRU bit changed - if (bCommInit && ((c^Chipset.IORam[d]) & EIRU) != 0) + // EIRU bit changed + if (((c^Chipset.IORam[d]) & EIRU) != 0) { // save new value for COM open Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); // reopen COM port with new setting - bCommInit = CommOpen(szSerialWire,szSerialIr); + CommOpen(szSerialWire,szSerialIr); } Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); #if defined DEBUG_SERIAL diff --git a/Sources/Emu48/MRU.C b/Sources/Emu48/MRU.C index baf367c..a72e4a9 100644 --- a/Sources/Emu48/MRU.C +++ b/Sources/Emu48/MRU.C @@ -84,7 +84,7 @@ VOID MruCleanup(VOID) { for (i = 0; i < nEntry; ++i) // cleanup each entry { - if (ppszFiles[i] != NULL) + if (ppszFiles[i] != NULL) // valid entry free(ppszFiles[i]); // cleanup entry } @@ -111,7 +111,7 @@ VOID MruAdd(LPCTSTR lpszEntry) for (i = 0; i < nEntry; ++i) { // already in table -> quit - if ( ppszFiles[i] != NULL + if ( ppszFiles[i] != NULL // valid entry && lstrcmpi(ppszFiles[i],szFilename) == 0) { MruMoveTop(i); // move to top and update menu @@ -120,7 +120,7 @@ VOID MruAdd(LPCTSTR lpszEntry) } i = nEntry - 1; // last index - if (ppszFiles[i] != NULL) + if (ppszFiles[i] != NULL) // valid entry free(ppszFiles[i]); // free oldest entry for (; i > 0; --i) // move old entries 1 line down @@ -173,16 +173,43 @@ UINT MruEntries(VOID) return nEntry; } -LPCTSTR MruFilename(UINT nIndex) +UINT MruID(LPCTSTR lpszEntry) { - LPCTSTR lpszName = _T(""); + TCHAR szFilename[MAX_PATH]; + LPTSTR lpFilePart; + UINT i; + + if (ppszFiles != NULL) // MRU initialized + { + _ASSERT(nEntry > 0); // must have entries + + // get full path name + GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart); + + // look if entry is already in table + for (i = 0; i < nEntry; ++i) + { + if ( ppszFiles[i] != NULL // valid entry + && lstrcmpi(ppszFiles[i],szFilename) == 0) + { + return i; // return ID + } + } + } + return (UINT) -1; // not found +} + +VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize) +{ + *szFilename = 0; // not found // MRU initialized and index inside valid range if (ppszFiles != NULL && nIndex < nEntry) { - lpszName = ppszFiles[nIndex]; + _ASSERT(ppszFiles[nIndex] != NULL); // valid entry + lstrcpyn(szFilename,ppszFiles[nIndex],nBuffersize); } - return lpszName; + return; } VOID MruUpdateMenu(HMENU hMenu) @@ -312,7 +339,7 @@ VOID MruWriteList(VOID) { _ASSERT(ppszFiles != NULL); // MRU not initialized wsprintf(szItemname,_T("File%d"),i+1); - if (ppszFiles[i] != NULL) + if (ppszFiles[i] != NULL) // valid entry { WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]); } @@ -338,7 +365,7 @@ VOID MruReadList(VOID) wsprintf(szItemname,_T("File%d"),i+1); ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename)); - if (ppszFiles[i] != NULL) // already filled + if (ppszFiles[i] != NULL) // valid entry { free(ppszFiles[i]); // free entry ppszFiles[i] = NULL; // clear last line diff --git a/Sources/Emu48/PCH.H b/Sources/Emu48/PCH.H index 31cb02a..a905b1c 100644 --- a/Sources/Emu48/PCH.H +++ b/Sources/Emu48/PCH.H @@ -51,6 +51,7 @@ #endif #if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier +#define __unaligned #define SetWindowLongPtr SetWindowLong #define GetWindowLongPtr GetWindowLong #define SetClassLongPtr SetClassLong diff --git a/Sources/Emu48/SERIAL.C b/Sources/Emu48/SERIAL.C index 6a6d816..c5b7a5b 100644 --- a/Sources/Emu48/SERIAL.C +++ b/Sources/Emu48/SERIAL.C @@ -93,6 +93,11 @@ static DWORD WINAPI EventThread(LPVOID pParam) UNREFERENCED_PARAMETER(pParam); } +BOOL CommIsOpen(VOID) +{ + return hComm != NULL; // have COM port handle +} + BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) { COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L }; @@ -347,7 +352,7 @@ VOID CommReceive(VOID) // reject reading if com port is closed and not whole operation if (hComm && dwBytesRead == 0L) // com port open and buffer empty { - if (ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE) + if (ReadFile(hComm,cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE) dwBytesRead = 0L; else // bytes received nRp = 0; // reset read pointer diff --git a/Sources/GCCPatch/EMU48GCC.RC b/Sources/GCCPatch/EMU48GCC.RC index 0f98eb3..c10be25 100644 --- a/Sources/GCCPatch/EMU48GCC.RC +++ b/Sources/GCCPatch/EMU48GCC.RC @@ -303,7 +303,7 @@ FONT 8, "MS Sans Serif" BEGIN ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP - LTEXT "Copyright © 2021 Christoph Gießelink && Sébastien Carlier", + LTEXT "Copyright © 2022 Christoph Gießelink && Sébastien Carlier", IDC_STATIC,29,18,181,8 DEFPUSHBUTTON "OK",IDOK,215,12,39,14 EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | @@ -752,8 +752,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,4,0 - PRODUCTVERSION 1,6,4,0 + FILEVERSION 1,6,5,0 + PRODUCTVERSION 1,6,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -770,12 +770,12 @@ BEGIN BEGIN VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 6, 4, 0\0" + VALUE "FileVersion", "1, 6, 5, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2021\0" + VALUE "LegalCopyright", "Copyright © 2022\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 6, 4, 0\0" + VALUE "ProductVersion", "1, 6, 5, 0\0" END END BLOCK "VarFileInfo" diff --git a/Sources/GCCPatch/PCH.H b/Sources/GCCPatch/PCH.H index 8894c6e..7bc6e95 100644 --- a/Sources/GCCPatch/PCH.H +++ b/Sources/GCCPatch/PCH.H @@ -22,6 +22,8 @@ #define IDC_HAND MAKEINTRESOURCE(32649) #endif +#define __unaligned + // normally defined in STDLIB.H #if !defined __max #define __max(a,b) (((a) > (b)) ? (a) : (b)) diff --git a/Sources/GCCPatch/README.TXT b/Sources/GCCPatch/README.TXT index 4c92712..88a235b 100644 --- a/Sources/GCCPatch/README.TXT +++ b/Sources/GCCPatch/README.TXT @@ -67,4 +67,4 @@ Many thanks to Pedro A. Arranda Guti compatible. -09/26/21 (c) by Christoph Gießelink +07/19/22 (c) by Christoph Gießelink diff --git a/Sources/MkShared/MKSHARED.C b/Sources/MkShared/MKSHARED.C index 9a7172f..5383c4c 100644 --- a/Sources/MkShared/MKSHARED.C +++ b/Sources/MkShared/MKSHARED.C @@ -20,11 +20,44 @@ #define WIN32_LEAN_AND_MEAN #define WIN32_EXTRA_LEAN #include +#include #include #include #include #include "resource.h" +#if _MSC_VER >= 1400 // valid for VS2005 and later +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='x86' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#elif defined _M_IA64 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='ia64' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='amd64' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='*' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#endif +#endif + #define _KB(n) (2*(n)*1024) #define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) @@ -61,11 +94,11 @@ static BOOL WriteCardFile(LPCTSTR strFilename,INT nBlocks) { DWORD dwWritten; - LPBYTE pbyBuffer = LocalAlloc(LPTR,_KB(1)); + LPBYTE pbyBuffer = (LPBYTE) calloc(1,_KB(1)); while (nBlocks--) WriteFile(hFile, pbyBuffer, _KB(1), &dwWritten, NULL); - LocalFree(pbyBuffer); + free(pbyBuffer); CloseHandle(hFile); return FALSE; @@ -192,7 +225,7 @@ INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpszCmdLine,INT nCmdSho wc.lpszClassName = _T("CMkShared"); RegisterClass(&wc); - hWnd = CreateDialog(hInst,MAKEINTRESOURCE(IDD_MAIN),0,WndProc); + hWnd = CreateDialog(hInst,MAKEINTRESOURCE(IDD_MAIN),0,(DLGPROC) WndProc); _ASSERT(hWnd); #if 0 diff --git a/Sources/MkShared/MKSHARED.DSP b/Sources/MkShared/MKSHARED.DSP index 0ca4a35..19c7301 100644 --- a/Sources/MkShared/MKSHARED.DSP +++ b/Sources/MkShared/MKSHARED.DSP @@ -7,19 +7,19 @@ CFG=MKSHARED - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run -!MESSAGE +!MESSAGE !MESSAGE NMAKE /f "MKSHARED.MAK". -!MESSAGE +!MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE +!MESSAGE !MESSAGE NMAKE /f "MKSHARED.MAK" CFG="MKSHARED - Win32 Release" -!MESSAGE +!MESSAGE !MESSAGE Possible choices for configuration are: -!MESSAGE +!MESSAGE !MESSAGE "MKSHARED - Win32 Release" (based on "Win32 (x86) Application") !MESSAGE "MKSHARED - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE +!MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 @@ -38,8 +38,8 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".\Release" -# PROP Intermediate_Dir ".\Release" +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c @@ -59,13 +59,13 @@ LINK32=link.exe # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "MKSHARED___" -# PROP BASE Intermediate_Dir "MKSHARED___" +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".\Debug" -# PROP Intermediate_Dir ".\Debug" +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c @@ -81,7 +81,7 @@ LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -!ENDIF +!ENDIF # Begin Target diff --git a/Sources/MkShared/MKSHARED.RC b/Sources/MkShared/MKSHARED.RC index 79d01a5..dab4008 100644 --- a/Sources/MkShared/MKSHARED.RC +++ b/Sources/MkShared/MKSHARED.RC @@ -139,8 +139,8 @@ IDI_MKSHARED ICON DISCARDABLE "MkShared.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,0,0 - PRODUCTVERSION 1,5,0,0 + FILEVERSION 1,6,0,0 + PRODUCTVERSION 1,6,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -157,12 +157,12 @@ BEGIN BEGIN VALUE "CompanyName", "Christoph Gießelink\0" VALUE "FileDescription", "HP48 RAM Card Creator for Emu48\0" - VALUE "FileVersion", "1, 5, 0, 0\0" + VALUE "FileVersion", "1, 6, 0, 0\0" VALUE "InternalName", "MkShared\0" - VALUE "LegalCopyright", "Copyright © 2006\0" + VALUE "LegalCopyright", "Copyright © 2020\0" VALUE "OriginalFilename", "MkShared.exe\0" VALUE "ProductName", "MkShared\0" - VALUE "ProductVersion", "1, 5, 0, 0\0" + VALUE "ProductVersion", "1, 6, 0, 0\0" END END BLOCK "VarFileInfo" diff --git a/uninst.exe b/uninst.exe index d977b9d28c51dad2bfc3cf0e4749fea377f99bc5..0d136b75298e29a0dafc966c8510dd228b1704c4 100755 GIT binary patch delta 66 zcmZqaVrl7O*)Z=ACo2OR10w?i1MBAHhg=yMO((xSYz-tej|4IrO|Cv-3uNy+;tnJk TkJ>YuZgxDn-=3u>?;9Hc%hnd~ delta 66 zcmZqaVrl7O*)Z=ACkq1`10w?i1Iy;+hg=yMO(wrRYz-tej|4IrPOd&;3uNy+;tnJk TkJ>YuY<4`l-=5|14g+xj%aIn;