mirror of
https://github.com/dgis/emu48android
synced 2024-12-26 09:58:49 +01:00
Version 2.6 (2022-08-19)
- Updated source code from Eric Rechlin's Emu48 version 1.64+ that was merged from Christoph Gießelink's Emu48 version 1.65. This new version improve the serial communication.
This commit is contained in:
parent
d27d777153
commit
bc8bd5b821
24 changed files with 633 additions and 295 deletions
|
@ -58,6 +58,11 @@ LINKS
|
||||||
|
|
||||||
CHANGES
|
CHANGES
|
||||||
|
|
||||||
|
Version 2.6 (2022-08-19)
|
||||||
|
|
||||||
|
- Updated source code from Eric Rechlin's Emu48 version 1.64+ that was merged from Christoph Gießelink's Emu48 version 1.65. This new version improve the serial communication.
|
||||||
|
|
||||||
|
|
||||||
Version 2.5 (2022-03-03)
|
Version 2.5 (2022-03-03)
|
||||||
|
|
||||||
- Allow to load RLE4, RLE8 and monochrome BMP images.
|
- Allow to load RLE4, RLE8 and monochrome BMP images.
|
||||||
|
@ -262,7 +267,7 @@ TODO
|
||||||
|
|
||||||
BUILD
|
BUILD
|
||||||
|
|
||||||
Emu48 for Android is built with Android Studio 2020.3.1 (2021).
|
Emu48 for Android is built with Android Studio 2021.1.1 (2022).
|
||||||
And to generate an installable APK file with a real Android device, it MUST be signed.
|
And to generate an installable APK file with a real Android device, it MUST be signed.
|
||||||
|
|
||||||
Either use Android Studio:
|
Either use Android Studio:
|
||||||
|
|
|
@ -28,13 +28,13 @@ if (keystorePropertiesFile.exists()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 31
|
compileSdkVersion 32
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.emulator.forty.eight"
|
applicationId "org.emulator.forty.eight"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 31
|
targetSdkVersion 32
|
||||||
versionCode 24
|
versionCode 25
|
||||||
versionName "2.5"
|
versionName "2.6"
|
||||||
setProperty("archivesBaseName", "Emu48-v$versionName")
|
setProperty("archivesBaseName", "Emu48-v$versionName")
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
@ -84,10 +84,10 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
implementation 'androidx.appcompat:appcompat:1.4.2'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
implementation 'androidx.preference:preference:1.2.0'
|
implementation 'androidx.preference:preference:1.2.0'
|
||||||
implementation 'com.google.android.material:material:1.5.0'
|
implementation 'com.google.android.material:material:1.6.1'
|
||||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||||
|
|
|
@ -34,7 +34,8 @@ h3 { color:red; font-size:1.1em; }
|
||||||
<div id="navi">
|
<div id="navi">
|
||||||
<p><a class="nav1" href="#s1">1. General</a></p>
|
<p><a class="nav1" href="#s1">1. General</a></p>
|
||||||
<p><a class="nav1" href="#s2">2. Acknowledgements</a></p>
|
<p><a class="nav1" href="#s2">2. Acknowledgements</a></p>
|
||||||
<p><a class="nav1" href="#s3">3. ROM Images</a></p>
|
<p><a class="nav1" href="#s3">3. ROM Images</a><br>
|
||||||
|
<a class="nav2" href="#ss3.1">3.1 Creation examples</a></p>
|
||||||
<p><a class="nav1" href="#s4">4. Installation</a></p>
|
<p><a class="nav1" href="#s4">4. Installation</a></p>
|
||||||
<p><a class="nav1" href="#s5">5. How to Start</a></p>
|
<p><a class="nav1" href="#s5">5. How to Start</a></p>
|
||||||
<p><a class="nav1" href="#s6">6. Command Line</a></p>
|
<p><a class="nav1" href="#s6">6. Command Line</a></p>
|
||||||
|
@ -83,12 +84,11 @@ h3 { color:red; font-size:1.1em; }
|
||||||
<a href="#ss12.2">12.2 About Emu48...</a>
|
<a href="#ss12.2">12.2 About Emu48...</a>
|
||||||
</span></p>
|
</span></p>
|
||||||
<p><a class="nav1" href="#s13">13. DDE Server</a></p>
|
<p><a class="nav1" href="#s13">13. DDE Server</a></p>
|
||||||
<p><a class="nav1" href="#s14">14. Emu48+ Changes</a></p>
|
<p><a class="nav1" href="#s14">14. License</a></p>
|
||||||
<p><a class="nav1" href="#s15">15. License</a></p>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<h1><a name=s1>1. General</a></h1>
|
<h1><a name=s1>1. General</a></h1>
|
||||||
<p><a href="http://hp.giesselink.com/emu42.htm">Emu48</a> is an
|
<p><a href="https://hp.giesselink.com/emu48.htm">Emu48</a> is an
|
||||||
emulator for the Hewlett Packard HP38G, HP39G, HP40G, HP48SX, HP48GX
|
emulator for the Hewlett Packard HP38G, HP39G, HP40G, HP48SX, HP48GX
|
||||||
and HP49G calculator hardware. These calculators are based on the
|
and HP49G calculator hardware. These calculators are based on the
|
||||||
1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
|
1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
|
||||||
|
@ -127,8 +127,28 @@ h3 { color:red; font-size:1.1em; }
|
||||||
in the destination file with zeros. Final notice, the convert
|
in the destination file with zeros. Final notice, the convert
|
||||||
utility shows the CRC result after the file convert and a passed
|
utility shows the CRC result after the file convert and a passed
|
||||||
ROM CRC test does <u><b>not</b></u> imply, that the source file
|
ROM CRC test does <u><b>not</b></u> 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.
|
||||||
</p>
|
</p>
|
||||||
|
<p>The general syntax of the convert utility is:</p>
|
||||||
|
<blockquote>Convert [-p] <old-rom-dump> [<new-rom-dump>]</blockquote>
|
||||||
|
<p>where:</p>
|
||||||
|
<blockquote>Convert <old-rom-dump></blockquote>
|
||||||
|
<p>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.
|
||||||
|
</p>
|
||||||
|
<p>where:</p>
|
||||||
|
<blockquote>Convert <old-rom-dump> <new-rom-dump></blockquote>
|
||||||
|
<p>convert the file <old-rom-dump> into the <u>unpacked</u>
|
||||||
|
ROM image file <new-rom-dump> valid for use in Emu48.
|
||||||
|
</p>
|
||||||
|
<p>where:</p>
|
||||||
|
<blockquote>Convert -p <old-rom-dump> <new-rom-dump></blockquote>
|
||||||
|
<p>convert the file <old-rom-dump> into the <u>packed</u>
|
||||||
|
ROM image file <new-rom-dump> valid for use in Emu48.
|
||||||
|
</p>
|
||||||
|
<h2><a name=ss3.1>3.1 Creation examples</a></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>HP38
|
<li>HP38
|
||||||
<p>To upload the ROM of your HP38G, you will need a special aplet
|
<p>To upload the ROM of your HP38G, you will need a special aplet
|
||||||
|
@ -137,18 +157,22 @@ h3 { color:red; font-size:1.1em; }
|
||||||
Convert utility.</p>
|
Convert utility.</p>
|
||||||
<p>To do that, start a Command Prompt while running Windows, and
|
<p>To do that, start a Command Prompt while running Windows, and
|
||||||
type:</p>
|
type:</p>
|
||||||
<blockquote>Convert <rom-file> ROM.38G</blockquote>
|
<blockquote>Convert -p <rom-file> ROM.38G</blockquote>
|
||||||
<p>Where <rom-file> is the path to your ROM image. This will
|
<p>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.
|
create a packed file named ROM.38G. This tool will also check its validity.
|
||||||
</p></li>
|
</p></li>
|
||||||
<li>HP39/40
|
<li>HP39/40
|
||||||
<p>To upload the ROM of your HP39G/HP40G, you will need a special aplet
|
<p>To upload the ROM of your HP39G/HP40G, you will need a special aplet
|
||||||
called <a href="http://hp.giesselink.com/emu48.htm">"ROM UPLOAD"</a>.
|
called <a href="https://hp.giesselink.com/emu48.htm">"ROM UPLOAD"</a>.
|
||||||
Once you've uploaded the ROM, you have to convert it using the Rom2emu utility.
|
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.
|
||||||
</p>
|
</p>
|
||||||
<p>To do that, start a Command Prompt while running Windows, and
|
<p>To do that, start a Command Prompt while running Windows, and
|
||||||
type:</p>
|
type:</p>
|
||||||
<blockquote>Rom2emu <rom-file> ROM.39G</blockquote>
|
<blockquote>Rom2emu <rom-file> ROM.39G</blockquote>
|
||||||
|
<p>or</p>
|
||||||
|
<blockquote>rename <rom-file> ROM.39G</blockquote>
|
||||||
<p>There's also a HP39G/HP40G beta ROM for emulators inside an old
|
<p>There's also a HP39G/HP40G beta ROM for emulators inside an old
|
||||||
<a href="http://www.hpcalc.org/details.php?id=4272">Emu48 package</a>.
|
<a href="http://www.hpcalc.org/details.php?id=4272">Emu48 package</a>.
|
||||||
</p></li>
|
</p></li>
|
||||||
|
@ -162,28 +186,28 @@ h3 { color:red; font-size:1.1em; }
|
||||||
<p>or</p>
|
<p>or</p>
|
||||||
<blockquote>Convert <rom-file> ROM.48S</blockquote>
|
<blockquote>Convert <rom-file> ROM.48S</blockquote>
|
||||||
<p>Where <rom-file> is the path to your old ROM image. This
|
<p>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
|
will create a file named ROM.48G or ROM.48S, depending on the
|
||||||
you own. This tool should be able to read any style of ROM image, and
|
version you own. This tool should be able to read any style of
|
||||||
will also check its validity. Note that if you run it with only one
|
ROM image, and will also check its validity. Note that if you run
|
||||||
parameter, no file will be written, but it will still check the
|
it with only one parameter, no file will be written, but it will
|
||||||
validity of the ROM.</p>
|
still check the validity of the ROM.</p>
|
||||||
<p>If you have never used an HP48 emulator, and don't have a ROM
|
<p>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
|
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
|
ROMDump Wizard V1.x, which will almost automatically get the ROM
|
||||||
your HP48. After the download you may have to convert your dump with
|
from your HP48. After the download you may have to convert your
|
||||||
the CONVERT utility into the Emu48 format.</p>
|
dump with the CONVERT utility into the Emu48 format.</p>
|
||||||
<p>You can find the latest version of the ROM dump programs on:</p>
|
<p>You can find the latest version of the ROM dump programs on:</p>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
ROMUPL.BIN <a href="http://www.hpcalc.org/details.php?id=3686">
|
ROMUPL.BIN <a href="http://www.hpcalc.org/details.php?id=3686">
|
||||||
http://www.hpcalc.org/details.php?id=3686</a><br>
|
http://www.hpcalc.org/details.php?id=3686</a><br>
|
||||||
ROMDump Wizard
|
ROMDump Wizard
|
||||||
<a href="http://hp.giesselink.com/emu48.htm">
|
<a href="https://hp.giesselink.com/emu48.htm">
|
||||||
http://hp.giesselink.com/emu48.htm</a>
|
https://hp.giesselink.com/emu48.htm</a>
|
||||||
</blockquote></li>
|
</blockquote></li>
|
||||||
<li>HP49G
|
<li>HP49G
|
||||||
<p>There's no ROM download program available so far. But you can
|
<p>There's no ROM download program available so far. But you can
|
||||||
create a ROM image with the
|
create a ROM image with the
|
||||||
<a href="http://hp.giesselink.com/emu48.htm">UPD49ROM tool</a>
|
<a href="https://hp.giesselink.com/emu48.htm">UPD49ROM tool</a>
|
||||||
and a <a href="http://www.hpcalc.org/hp49/pc/rom/">
|
and a <a href="http://www.hpcalc.org/hp49/pc/rom/">
|
||||||
ROM update file</a> for the HP49G calculator. I suggested to use
|
ROM update file</a> for the HP49G calculator. I suggested to use
|
||||||
<a href="http://www.hpcalc.org/details.php?id=3240">version 1.19-6</a>
|
<a href="http://www.hpcalc.org/details.php?id=3240">version 1.19-6</a>
|
||||||
|
@ -239,7 +263,7 @@ h3 { color:red; font-size:1.1em; }
|
||||||
<p>If you want other great scripts, visit Rechlin's great HP archive
|
<p>If you want other great scripts, visit Rechlin's great HP archive
|
||||||
<a href="http://www.hpcalc.org/"></a></p>
|
<a href="http://www.hpcalc.org/"></a></p>
|
||||||
<p>If you are interested in writing new scripts, get the KML 2.0
|
<p>If you are interested in writing new scripts, get the KML 2.0
|
||||||
documentation from <a href="http://hp.giesselink.com/emu48.htm">the
|
documentation from <a href="https://hp.giesselink.com/emu48.htm">the
|
||||||
authors Emu48 page</a>.</p>
|
authors Emu48 page</a>.</p>
|
||||||
<p>Having selected a script, press OK to start the emulator. In most
|
<p>Having selected a script, press OK to start the emulator. In most
|
||||||
cases, when Emu48 crash after pressing the OK button, you are using
|
cases, when Emu48 crash after pressing the OK button, you are using
|
||||||
|
@ -462,7 +486,7 @@ h3 { color:red; font-size:1.1em; }
|
||||||
simulation. The data transfer to the printer simulator is done over UDP.
|
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
|
In this section you can the define the IPv4 address and the port the
|
||||||
printer simulator is listening. A suitable HP82240B printer simulation can
|
printer simulator is listening. A suitable HP82240B printer simulation can
|
||||||
be found <a href="http://hp.giesselink.com/hp82240b.htm">here</a>.</p>
|
be found <a href="https://hp.giesselink.com/hp82240b.htm">here</a>.</p>
|
||||||
<h4>8.6.3.3 Section Serial Ports</h4>
|
<h4>8.6.3.3 Section Serial Ports</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><i>Wire</i>
|
<li><i>Wire</i>
|
||||||
|
@ -651,7 +675,7 @@ h3 { color:red; font-size:1.1em; }
|
||||||
Cyrille de Brebisson of Hewlett-Packard.</p>
|
Cyrille de Brebisson of Hewlett-Packard.</p>
|
||||||
<h1><a name=s15>15. License</a></h1>
|
<h1><a name=s15>15. License</a></h1>
|
||||||
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
|
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
|
||||||
Copyright (C) 2021 Christoph Gießelink</p>
|
Copyright (C) 2022 Christoph Gießelink</p>
|
||||||
<p>This program is free software; you can redistribute it and/or modify it
|
<p>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
|
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)
|
Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
|
|
@ -58,6 +58,11 @@ LINKS
|
||||||
|
|
||||||
CHANGES
|
CHANGES
|
||||||
|
|
||||||
|
Version 2.6 (2022-08-19)
|
||||||
|
|
||||||
|
- Updated source code from Eric Rechlin's Emu48 version 1.64+ that was merged from Christoph Gießelink's Emu48 version 1.65. This new version improve the serial communication.
|
||||||
|
|
||||||
|
|
||||||
Version 2.5 (2022-03-03)
|
Version 2.5 (2022-03-03)
|
||||||
|
|
||||||
- Allow to load RLE4, RLE8 and monochrome BMP images.
|
- Allow to load RLE4, RLE8 and monochrome BMP images.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "kml.h"
|
#include "kml.h"
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
|
|
||||||
#define VERSION "1.63+"
|
#define VERSION "1.64+"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
|
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
|
||||||
|
@ -681,7 +681,7 @@ static INT_PTR CALLBACK SettingsPeripheralProc(HWND hDlg, UINT uMsg, WPARAM wPar
|
||||||
|
|
||||||
// set combobox parameter
|
// set combobox parameter
|
||||||
SetCommList(hDlg,szSerialWire,szSerialIr);
|
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_WIRE),FALSE);
|
||||||
EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE);
|
EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE);
|
||||||
|
@ -768,7 +768,10 @@ static UINT SaveChanges(BOOL bAuto)
|
||||||
if (GetSaveAsFilename())
|
if (GetSaveAsFilename())
|
||||||
{
|
{
|
||||||
if (SaveDocumentAs(szBufferFilename))
|
if (SaveDocumentAs(szBufferFilename))
|
||||||
|
{
|
||||||
|
MruAdd(szBufferFilename);
|
||||||
return IDYES;
|
return IDYES;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return IDCANCEL;
|
return IDCANCEL;
|
||||||
}
|
}
|
||||||
|
@ -776,6 +779,7 @@ static UINT SaveChanges(BOOL bAuto)
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveDocument();
|
SaveDocument();
|
||||||
|
MruAdd(szCurrentFilename);
|
||||||
return IDYES;
|
return IDYES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,25 +1060,32 @@ cancel:
|
||||||
//
|
//
|
||||||
static LRESULT OnFileMruOpen(UINT wID)
|
static LRESULT OnFileMruOpen(UINT wID)
|
||||||
{
|
{
|
||||||
LPCTSTR lpszFilename;
|
TCHAR szFilename[MAX_PATH];
|
||||||
|
|
||||||
wID -= ID_FILE_MRU_FILE1; // zero based MRU index
|
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)
|
if (bDocumentAvail)
|
||||||
{
|
{
|
||||||
SwitchToState(SM_INVALID);
|
SwitchToState(SM_INVALID);
|
||||||
|
// saving may change MRU index and destroy lpszFilename pointer content
|
||||||
if (IDCANCEL == SaveChanges(bAutoSave))
|
if (IDCANCEL == SaveChanges(bAutoSave))
|
||||||
goto cancel;
|
goto cancel;
|
||||||
}
|
}
|
||||||
if (!OpenDocument(lpszFilename)) // document loading failed
|
if (!OpenDocument(szFilename)) // document loading failed
|
||||||
|
{
|
||||||
|
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
|
MruRemove(wID); // entry not valid any more
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MruMoveTop(wID); // move entry to top of MRU list
|
MruAdd(szFilename); // add entry to top of MRU list
|
||||||
}
|
}
|
||||||
cancel:
|
cancel:
|
||||||
if (pbyRom) SwitchToState(SM_RUN);
|
if (pbyRom) SwitchToState(SM_RUN);
|
||||||
|
|
|
@ -133,7 +133,8 @@ extern VOID MruAdd(LPCTSTR lpszEntry);
|
||||||
extern VOID MruRemove(UINT nIndex);
|
extern VOID MruRemove(UINT nIndex);
|
||||||
extern VOID MruMoveTop(UINT nIndex);
|
extern VOID MruMoveTop(UINT nIndex);
|
||||||
extern UINT MruEntries(VOID);
|
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 MruUpdateMenu(HMENU hMenu);
|
||||||
extern VOID MruWriteList(VOID);
|
extern VOID MruWriteList(VOID);
|
||||||
extern VOID MruReadList(VOID);
|
extern VOID MruReadList(VOID);
|
||||||
|
@ -193,7 +194,6 @@ extern BOOL bRealSpeed;
|
||||||
extern BOOL bKeySlow;
|
extern BOOL bKeySlow;
|
||||||
extern BOOL bSoundSlow;
|
extern BOOL bSoundSlow;
|
||||||
extern UINT nOpcSlow;
|
extern UINT nOpcSlow;
|
||||||
extern BOOL bCommInit;
|
|
||||||
extern CHIPSET Chipset;
|
extern CHIPSET Chipset;
|
||||||
extern TCHAR szSerialWire[16];
|
extern TCHAR szSerialWire[16];
|
||||||
extern TCHAR szSerialIr[16];
|
extern TCHAR szSerialIr[16];
|
||||||
|
@ -412,6 +412,7 @@ extern LPCTSTR RplGetName(DWORD dwAddr);
|
||||||
extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr);
|
extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr);
|
||||||
|
|
||||||
// Serial.c
|
// Serial.c
|
||||||
|
extern BOOL CommIsOpen(VOID);
|
||||||
extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort);
|
extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort);
|
||||||
extern VOID CommClose(VOID);
|
extern VOID CommClose(VOID);
|
||||||
extern VOID CommSetBaud(VOID);
|
extern VOID CommSetBaud(VOID);
|
||||||
|
|
|
@ -22,7 +22,6 @@ BOOL bRealSpeed = FALSE;
|
||||||
BOOL bKeySlow = FALSE; // slow down for key emulation
|
BOOL bKeySlow = FALSE; // slow down for key emulation
|
||||||
BOOL bSoundSlow = FALSE; // slow down for sound emulation
|
BOOL bSoundSlow = FALSE; // slow down for sound emulation
|
||||||
UINT nOpcSlow = 0; // no. of opcodes to slow down
|
UINT nOpcSlow = 0; // no. of opcodes to slow down
|
||||||
BOOL bCommInit = FALSE; // COM port not open
|
|
||||||
|
|
||||||
CHIPSET Chipset;
|
CHIPSET Chipset;
|
||||||
|
|
||||||
|
@ -353,16 +352,15 @@ static __inline VOID SetT2Cycles(VOID) // set device specific cpu cycles in int
|
||||||
VOID CheckSerial(VOID)
|
VOID CheckSerial(VOID)
|
||||||
{
|
{
|
||||||
// COM port closed and serial on
|
// 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
|
// 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
|
CommClose(); // close COM port
|
||||||
bCommInit = FALSE;
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -551,7 +549,6 @@ loop:
|
||||||
{
|
{
|
||||||
OnToolMacroStop(); // close open keyboard macro handler
|
OnToolMacroStop(); // close open keyboard macro handler
|
||||||
CommClose(); // close COM port
|
CommClose(); // close COM port
|
||||||
bCommInit = FALSE; // COM port not open
|
|
||||||
nState = SM_INVALID; // in invalid state
|
nState = SM_INVALID; // in invalid state
|
||||||
WaitForSingleObject(hEventShutdn,INFINITE);
|
WaitForSingleObject(hEventShutdn,INFINITE);
|
||||||
if (nNextState == SM_RETURN) // go into return state
|
if (nNextState == SM_RETURN) // go into return state
|
||||||
|
|
|
@ -1730,7 +1730,7 @@ typedef struct _BmpFile
|
||||||
LPBYTE pbyFile; // buffer
|
LPBYTE pbyFile; // buffer
|
||||||
} BMPFILE, FAR *LPBMPFILE, *PBMPFILE;
|
} 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;
|
if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed;
|
||||||
|
|
||||||
|
@ -1738,7 +1738,7 @@ static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi)
|
||||||
return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0;
|
return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
static HPALETTE CreateBIPalette(__unaligned BITMAPINFOHEADER CONST *lpbi)
|
||||||
{
|
{
|
||||||
LOGPALETTE* pPal;
|
LOGPALETTE* pPal;
|
||||||
HPALETTE hpal = NULL;
|
HPALETTE hpal = NULL;
|
||||||
|
@ -1747,12 +1747,9 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
||||||
BYTE green;
|
BYTE green;
|
||||||
BYTE blue;
|
BYTE blue;
|
||||||
UINT i;
|
UINT i;
|
||||||
RGBQUAD* pRgb;
|
__unaligned RGBQUAD* pRgb;
|
||||||
|
|
||||||
if (!lpbi)
|
if (!lpbi || lpbi->biSize != sizeof(BITMAPINFOHEADER))
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Get a pointer to the color table and the number of colors in it
|
// Get a pointer to the color table and the number of colors in it
|
||||||
|
@ -1816,22 +1813,19 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
||||||
|
|
||||||
static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
|
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);
|
dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||||
if (pBmp->dwFileSize < dwFileSize) return NULL;
|
if ( pBmp->dwFileSize < dwFileSize // minimum size to read data from BITMAPFILEHEADER + BITMAPINFOHEADER
|
||||||
|
|| pBmfh->bfType != 0x4D42) // "BM"
|
||||||
// check for bitmap
|
return NULL;
|
||||||
pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile;
|
|
||||||
if (pBmfh->bfType != 0x4D42) return NULL; // "BM"
|
|
||||||
|
|
||||||
pBmi = (LPBITMAPINFO) (pBmp->pbyFile + sizeof(BITMAPFILEHEADER));
|
|
||||||
|
|
||||||
// size with color table
|
// size with color table
|
||||||
if (pBmi->bmiHeader.biCompression == BI_BITFIELDS)
|
if (pBmi->bmiHeader.biCompression == BI_BITFIELDS)
|
||||||
|
@ -2452,11 +2446,15 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
|
||||||
if (hBitmap == NULL) goto quit;
|
if (hBitmap == NULL) goto quit;
|
||||||
|
|
||||||
pbySrc = pbyImage; // init source loop pointer
|
pbySrc = pbyImage; // init source loop pointer
|
||||||
|
pbyPixels += bmi.bmiHeader.biSizeImage; // end of destination bitmap
|
||||||
|
|
||||||
// fill bottom up DIB pixel buffer with color information
|
// 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)
|
for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth)
|
||||||
{
|
{
|
||||||
|
@ -2465,8 +2463,6 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
|
||||||
*pbyLine++ = pbySrc[0]; // red
|
*pbyLine++ = pbySrc[0]; // red
|
||||||
pbySrc += 3;
|
pbySrc += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bPalette && hPalette == NULL)
|
if (bPalette && hPalette == NULL)
|
||||||
|
@ -2482,12 +2478,6 @@ quit:
|
||||||
{
|
{
|
||||||
free(pbyImage); // free PNG image data
|
free(pbyImage); // free PNG image data
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hBitmap != NULL && uError != 0) // creation failed
|
|
||||||
{
|
|
||||||
DeleteObject(hBitmap); // delete bitmap
|
|
||||||
hBitmap = NULL;
|
|
||||||
}
|
|
||||||
return hBitmap;
|
return hBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
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*/
|
#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
|
||||||
#endif /*_MSC_VER */
|
#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.
|
with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
|
||||||
-Tools for C and common code for PNG and Zlib
|
-Tools for C and common code for PNG and Zlib
|
||||||
-C Code for Zlib (huffman, deflate, ...)
|
-C Code for Zlib (huffman, deflate, ...)
|
||||||
|
@ -267,7 +267,7 @@ typedef struct ucvector {
|
||||||
} ucvector;
|
} ucvector;
|
||||||
|
|
||||||
/*returns 1 if success, 0 if failure ==> nothing done*/
|
/*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) {
|
if(size > p->allocsize) {
|
||||||
size_t newsize = size + (p->allocsize >> 1u);
|
size_t newsize = size + (p->allocsize >> 1u);
|
||||||
void* data = lodepng_realloc(p->data, newsize);
|
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*/
|
else return 0; /*error: not enough memory*/
|
||||||
}
|
}
|
||||||
p->size = size;
|
|
||||||
return 1; /*success*/
|
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) {
|
static ucvector ucvector_init(unsigned char* buffer, size_t size) {
|
||||||
ucvector v;
|
ucvector v;
|
||||||
v.data = buffer;
|
v.data = buffer;
|
||||||
|
@ -480,71 +485,62 @@ static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned c
|
||||||
ensureBits functions:
|
ensureBits functions:
|
||||||
Ensures the reader can at least read nbits bits in one or more readBits calls,
|
Ensures the reader can at least read nbits bits in one or more readBits calls,
|
||||||
safely even if not enough bits are available.
|
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 */
|
/*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 start = reader->bp >> 3u;
|
||||||
size_t size = reader->size;
|
size_t size = reader->size;
|
||||||
if(start + 1u < size) {
|
if(start + 1u < size) {
|
||||||
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u);
|
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
return 1;
|
|
||||||
} else {
|
} else {
|
||||||
reader->buffer = 0;
|
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);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
return reader->bp + nbits <= reader->bitsize;
|
|
||||||
}
|
}
|
||||||
|
(void)nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*See ensureBits documentation above. This one ensures up to 17 bits */
|
/*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 start = reader->bp >> 3u;
|
||||||
size_t size = reader->size;
|
size_t size = reader->size;
|
||||||
if(start + 2u < size) {
|
if(start + 2u < size) {
|
||||||
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
|
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
|
||||||
((unsigned)reader->data[start + 2] << 16u);
|
((unsigned)reader->data[start + 2] << 16u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
return 1;
|
|
||||||
} else {
|
} else {
|
||||||
reader->buffer = 0;
|
reader->buffer = 0;
|
||||||
if(start + 0u < size) reader->buffer |= reader->data[start + 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 + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
return reader->bp + nbits <= reader->bitsize;
|
|
||||||
}
|
}
|
||||||
|
(void)nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*See ensureBits documentation above. This one ensures up to 25 bits */
|
/*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 start = reader->bp >> 3u;
|
||||||
size_t size = reader->size;
|
size_t size = reader->size;
|
||||||
if(start + 3u < size) {
|
if(start + 3u < size) {
|
||||||
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
|
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);
|
((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
return 1;
|
|
||||||
} else {
|
} else {
|
||||||
reader->buffer = 0;
|
reader->buffer = 0;
|
||||||
if(start + 0u < size) reader->buffer |= reader->data[start + 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 + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
|
||||||
if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
|
if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
return reader->bp + nbits <= reader->bitsize;
|
|
||||||
}
|
}
|
||||||
|
(void)nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*See ensureBits documentation above. This one ensures up to 32 bits */
|
/*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 start = reader->bp >> 3u;
|
||||||
size_t size = reader->size;
|
size_t size = reader->size;
|
||||||
if(start + 4u < 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);
|
((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
reader->buffer >>= (reader->bp & 7u);
|
||||||
reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u)));
|
reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u)));
|
||||||
return 1;
|
|
||||||
} else {
|
} else {
|
||||||
reader->buffer = 0;
|
reader->buffer = 0;
|
||||||
if(start + 0u < size) reader->buffer |= reader->data[start + 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 + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
|
||||||
if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u);
|
if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u);
|
||||||
reader->buffer >>= (reader->bp & 7u);
|
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. */
|
/* 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. */
|
/* The shift allows nbits to be only up to 31. */
|
||||||
return reader->buffer & ((1u << nbits) - 1u);
|
return reader->buffer & ((1u << nbits) - 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must have enough bits available with ensureBits */
|
/* 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->buffer >>= nbits;
|
||||||
reader->bp += nbits;
|
reader->bp += nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must have enough bits available with ensureBits */
|
/* 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);
|
unsigned result = peekBits(reader, nbits);
|
||||||
advanceBits(reader, nbits);
|
advanceBits(reader, nbits);
|
||||||
return result;
|
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*/
|
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||||
|
|
||||||
static unsigned reverseBits(unsigned bits, unsigned num) {
|
static unsigned reverseBits(unsigned bits, unsigned num) {
|
||||||
|
@ -736,10 +711,11 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
||||||
numpresent = 0;
|
numpresent = 0;
|
||||||
for(i = 0; i < tree->numcodes; ++i) {
|
for(i = 0; i < tree->numcodes; ++i) {
|
||||||
unsigned l = tree->lengths[i];
|
unsigned l = tree->lengths[i];
|
||||||
unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
|
unsigned symbol, reverse;
|
||||||
/*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
|
|
||||||
unsigned reverse = reverseBits(symbol, l);
|
|
||||||
if(l == 0) continue;
|
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++;
|
numpresent++;
|
||||||
|
|
||||||
if(l <= FIRSTBITS) {
|
if(l <= FIRSTBITS) {
|
||||||
|
@ -1103,11 +1079,10 @@ static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree*
|
||||||
advanceBits(reader, l);
|
advanceBits(reader, l);
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
unsigned index2;
|
|
||||||
advanceBits(reader, FIRSTBITS);
|
advanceBits(reader, FIRSTBITS);
|
||||||
index2 = value + peekBits(reader, l - FIRSTBITS);
|
value += peekBits(reader, l - FIRSTBITS);
|
||||||
advanceBits(reader, codetree->table_len[index2] - FIRSTBITS);
|
advanceBits(reader, codetree->table_len[value] - FIRSTBITS);
|
||||||
return codetree->table_value[index2];
|
return codetree->table_value[value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||||
|
@ -1140,7 +1115,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
|
||||||
unsigned* bitlen_cl = 0;
|
unsigned* bitlen_cl = 0;
|
||||||
HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
|
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*/
|
/*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
|
||||||
HLIT = readBits(reader, 5) + 257;
|
HLIT = readBits(reader, 5) + 257;
|
||||||
|
@ -1265,6 +1241,10 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
||||||
unsigned error = 0;
|
unsigned error = 0;
|
||||||
HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
|
HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
|
||||||
HuffmanTree tree_d; /*the huffman tree for distance 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_ll);
|
||||||
HuffmanTree_init(&tree_d);
|
HuffmanTree_init(&tree_d);
|
||||||
|
@ -1272,14 +1252,21 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
||||||
if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);
|
if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);
|
||||||
else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);
|
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*/
|
/*code_ll is literal, length or end code*/
|
||||||
unsigned code_ll;
|
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);
|
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(code_ll <= 255) /*literal symbol*/ {
|
||||||
if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/);
|
out->data[out->size++] = (unsigned char)code_ll;
|
||||||
out->data[out->size - 1] = (unsigned char)code_ll;
|
|
||||||
} else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {
|
} else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {
|
||||||
unsigned code_d, distance;
|
unsigned code_d, distance;
|
||||||
unsigned numextrabits_l, numextrabits_d; /*extra bits for length and 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];
|
numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
|
||||||
if(numextrabits_l != 0) {
|
if(numextrabits_l != 0) {
|
||||||
/* bits already ensured above */
|
/* bits already ensured above */
|
||||||
|
ensureBits25(reader, 5);
|
||||||
length += readBits(reader, numextrabits_l);
|
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*/
|
if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
|
||||||
backward = start - distance;
|
backward = start - distance;
|
||||||
|
|
||||||
if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/);
|
out->size += length;
|
||||||
if(distance < length) {
|
if(distance < length) {
|
||||||
size_t forward;
|
size_t forward;
|
||||||
lodepng_memcpy(out->data + start, out->data + backward, distance);
|
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);
|
lodepng_memcpy(out->data + start, out->data + backward, length);
|
||||||
}
|
}
|
||||||
} else if(code_ll == 256) {
|
} else if(code_ll == 256) {
|
||||||
break; /*end code, break the loop*/
|
done = 1; /*end code, finish the loop*/
|
||||||
} else /*if(code_ll == INVALIDSYMBOL)*/ {
|
} else /*if(code_ll == INVALIDSYMBOL)*/ {
|
||||||
ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
|
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*/
|
/*check if any of the ensureBits above went out of bounds*/
|
||||||
if(reader->bp > reader->bitsize) {
|
if(reader->bp > reader->bitsize) {
|
||||||
/*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
|
/*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*/
|
/*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*/
|
if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/
|
||||||
|
|
||||||
|
/*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);
|
lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
|
||||||
bytepos += LEN;
|
bytepos += LEN;
|
||||||
|
}
|
||||||
|
|
||||||
reader->bp = bytepos << 3u;
|
reader->bp = bytepos << 3u;
|
||||||
|
|
||||||
|
@ -1396,7 +1390,8 @@ static unsigned lodepng_inflatev(ucvector* out,
|
||||||
|
|
||||||
while(!BFINAL) {
|
while(!BFINAL) {
|
||||||
unsigned BTYPE;
|
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);
|
BFINAL = readBits(&reader, 1);
|
||||||
BTYPE = readBits(&reader, 2);
|
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 */
|
/* CRC polynomial: 0xedb88320 */
|
||||||
static unsigned lodepng_crc32_table[256] = {
|
static unsigned lodepng_crc32_table[256] = {
|
||||||
0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u,
|
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;
|
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);
|
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 / */
|
/* / 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) {
|
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) {
|
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) {
|
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
|
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) {
|
&& 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. */
|
/* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
|
||||||
return chunk + 8;
|
return chunk + 8;
|
||||||
} else {
|
} else {
|
||||||
size_t total_chunk_length;
|
size_t total_chunk_length;
|
||||||
unsigned char* result;
|
|
||||||
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
|
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
|
||||||
result = chunk + total_chunk_length;
|
if(total_chunk_length > available_size) return end; /*outside of range*/
|
||||||
if(result < chunk) return end; /*pointer overflow*/
|
return chunk + total_chunk_length;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) {
|
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
|
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) {
|
&& 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. */
|
/* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
|
||||||
return chunk + 8;
|
return chunk + 8;
|
||||||
} else {
|
} else {
|
||||||
size_t total_chunk_length;
|
size_t total_chunk_length;
|
||||||
const unsigned char* result;
|
|
||||||
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
|
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
|
||||||
result = chunk + total_chunk_length;
|
if(total_chunk_length > available_size) return end; /*outside of range*/
|
||||||
if(result < chunk) return end; /*pointer overflow*/
|
return chunk + total_chunk_length;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2586,7 +2581,7 @@ the data is at chunk + 8. To finalize chunk, add the data, then use
|
||||||
lodepng_chunk_generate_crc */
|
lodepng_chunk_generate_crc */
|
||||||
static unsigned lodepng_chunk_init(unsigned char** chunk,
|
static unsigned lodepng_chunk_init(unsigned char** chunk,
|
||||||
ucvector* out,
|
ucvector* out,
|
||||||
unsigned length, const char* type) {
|
size_t length, const char* type) {
|
||||||
size_t new_length = out->size;
|
size_t new_length = out->size;
|
||||||
if(lodepng_addofl(new_length, length, &new_length)) return 77;
|
if(lodepng_addofl(new_length, length, &new_length)) return 77;
|
||||||
if(lodepng_addofl(new_length, 12, &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;
|
*chunk = out->data + new_length - length - 12u;
|
||||||
|
|
||||||
/*1: length*/
|
/*1: length*/
|
||||||
lodepng_set32bitInt(*chunk, length);
|
lodepng_set32bitInt(*chunk, (unsigned)length);
|
||||||
|
|
||||||
/*2: chunk name (4 letters)*/
|
/*2: chunk name (4 letters)*/
|
||||||
lodepng_memcpy(*chunk + 4, type, 4);
|
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 */
|
/* like lodepng_chunk_create but with custom allocsize */
|
||||||
static unsigned lodepng_chunk_createv(ucvector* out,
|
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;
|
unsigned char* chunk;
|
||||||
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type));
|
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_name = NULL;
|
||||||
info->iccp_profile = 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);
|
LodePNGUnknownChunks_init(info);
|
||||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
#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
|
if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize
|
||||||
&& mode_in->bitdepth == mode_out->bitdepth) {
|
&& mode_in->bitdepth == mode_out->bitdepth) {
|
||||||
/*If input should have same palette colors, keep original to preserve its order and prevent conversion*/
|
/*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);
|
lodepng_color_mode_copy(mode_out, mode_in);
|
||||||
}
|
}
|
||||||
} else /*8-bit or 16-bit per channel*/ {
|
} 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. */
|
too much code. Whether this speeds up anything depends on compiler and settings. */
|
||||||
if(bytewidth >= 4) {
|
if(bytewidth >= 4) {
|
||||||
for(; i + 3 < length; i += 4, j += 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 s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3];
|
||||||
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
|
unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3];
|
||||||
unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
|
unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3];
|
||||||
unsigned char s3 = scanline[i + 3], r3 = recon[j + 3], p3 = precon[i + 3];
|
|
||||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||||
recon[i + 2] = s2 + ((r2 + p2) >> 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) {
|
} else if(bytewidth >= 3) {
|
||||||
for(; i + 2 < length; i += 3, j += 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 s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2];
|
||||||
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
|
unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2];
|
||||||
unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
|
unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2];
|
||||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||||
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
|
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
|
||||||
}
|
}
|
||||||
} else if(bytewidth >= 2) {
|
} else if(bytewidth >= 2) {
|
||||||
for(; i + 1 < length; i += 2, j += 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 s0 = scanline[i + 0], s1 = scanline[i + 1];
|
||||||
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[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 + 0] = s0 + ((r0 + p0) >> 1u);
|
||||||
recon[i + 1] = s1 + ((r1 + p1) >> 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*/
|
if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/
|
||||||
return error;
|
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*/
|
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||||
|
|
||||||
unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
|
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);
|
chunkLength = lodepng_chunk_length(chunk);
|
||||||
if(chunkLength > 2147483647) return 63;
|
if(chunkLength > 2147483647) return 63;
|
||||||
data = lodepng_chunk_data_const(chunk);
|
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")) {
|
if(lodepng_chunk_type_equals(chunk, "PLTE")) {
|
||||||
error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
|
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);
|
error = readChunk_sRGB(&state->info_png, data, chunkLength);
|
||||||
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
||||||
error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
|
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*/
|
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||||
} else {
|
} else {
|
||||||
/* unhandled chunk is ok (is not an error) */
|
/* unhandled chunk is ok (is not an error) */
|
||||||
|
@ -4791,7 +4832,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
||||||
LodePNGState* state,
|
LodePNGState* state,
|
||||||
const unsigned char* in, size_t insize) {
|
const unsigned char* in, size_t insize) {
|
||||||
unsigned char IEND = 0;
|
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*/
|
unsigned char* idat; /*the data from idat chunks, zlib compressed*/
|
||||||
size_t idatsize = 0;
|
size_t idatsize = 0;
|
||||||
unsigned char* scanlines = 0;
|
unsigned char* scanlines = 0;
|
||||||
|
@ -4827,14 +4868,15 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
||||||
while(!IEND && !state->error) {
|
while(!IEND && !state->error) {
|
||||||
unsigned chunkLength;
|
unsigned chunkLength;
|
||||||
const unsigned char* data; /*the data in the chunk*/
|
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*/
|
/*error: next chunk out of bounds of the in buffer*/
|
||||||
if((size_t)((chunk - in) + 12) > insize || chunk < in) {
|
if(chunk < in || pos + 12 > insize) {
|
||||||
if(state->decoder.ignore_end) break; /*other errors may still happen though*/
|
if(state->decoder.ignore_end) break; /*other errors may still happen though*/
|
||||||
CERROR_BREAK(state->error, 30);
|
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);
|
chunkLength = lodepng_chunk_length(chunk);
|
||||||
/*error: chunk length larger than the max PNG chunk size*/
|
/*error: chunk length larger than the max PNG chunk size*/
|
||||||
if(chunkLength > 2147483647) {
|
if(chunkLength > 2147483647) {
|
||||||
|
@ -4842,8 +4884,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
||||||
CERROR_BREAK(state->error, 63);
|
CERROR_BREAK(state->error, 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) {
|
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*/
|
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);
|
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")) {
|
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
||||||
state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
|
state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
|
||||||
if(state->error) break;
|
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*/
|
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||||
} else /*it's not an implemented chunk type, so ignore it: skip over the data*/ {
|
} 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)*/
|
/*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;
|
unsigned char* chunk;
|
||||||
size_t i, j = 8;
|
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) {
|
for(i = 0; i != info->palettesize; ++i) {
|
||||||
/*add all channels except alpha channel*/
|
/*add all channels except alpha channel*/
|
||||||
|
@ -5176,7 +5225,7 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) {
|
||||||
--amount;
|
--amount;
|
||||||
}
|
}
|
||||||
if(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*/
|
/*add the alpha channel values from the palette*/
|
||||||
for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3];
|
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);
|
error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings);
|
||||||
if(!error) {
|
if(!error) {
|
||||||
error = lodepng_chunk_createv(out, (unsigned)zlibsize, "IDAT", zlib);
|
error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib);
|
||||||
}
|
}
|
||||||
lodepng_free(zlib);
|
lodepng_free(zlib);
|
||||||
return error;
|
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 keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring);
|
||||||
size_t size = keysize + 1 + textsize;
|
size_t size = keysize + 1 + textsize;
|
||||||
if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/
|
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);
|
lodepng_memcpy(chunk + 8, keyword, keysize);
|
||||||
chunk[8 + keysize] = 0; /*null termination char*/
|
chunk[8 + keysize] = 0; /*null termination char*/
|
||||||
lodepng_memcpy(chunk + 9 + keysize, textstring, textsize);
|
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);
|
(const unsigned char*)textstring, textsize, zlibsettings);
|
||||||
if(!error) {
|
if(!error) {
|
||||||
size_t size = keysize + 2 + compressedsize;
|
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) {
|
if(!error) {
|
||||||
lodepng_memcpy(chunk + 8, keyword, keysize);
|
lodepng_memcpy(chunk + 8, keyword, keysize);
|
||||||
|
@ -5280,7 +5329,7 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyw
|
||||||
}
|
}
|
||||||
if(!error) {
|
if(!error) {
|
||||||
size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize);
|
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) {
|
if(!error) {
|
||||||
size_t pos = 8;
|
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);
|
info->iccp_profile, info->iccp_profile_size, zlibsettings);
|
||||||
if(!error) {
|
if(!error) {
|
||||||
size_t size = keysize + 2 + compressedsize;
|
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) {
|
if(!error) {
|
||||||
lodepng_memcpy(chunk + 8, info->iccp_name, keysize);
|
lodepng_memcpy(chunk + 8, info->iccp_name, keysize);
|
||||||
|
@ -5407,6 +5456,42 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom
|
||||||
return error;
|
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*/
|
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||||
|
|
||||||
static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
|
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);
|
ucvector outv = ucvector_init(NULL, 0);
|
||||||
LodePNGInfo info;
|
LodePNGInfo info;
|
||||||
const LodePNGInfo* info_png = &state->info_png;
|
const LodePNGInfo* info_png = &state->info_png;
|
||||||
|
LodePNGColorMode auto_color;
|
||||||
|
|
||||||
lodepng_info_init(&info);
|
lodepng_info_init(&info);
|
||||||
|
lodepng_color_mode_init(&auto_color);
|
||||||
|
|
||||||
/*provide some proper output values if error will happen*/
|
/*provide some proper output values if error will happen*/
|
||||||
*out = 0;
|
*out = 0;
|
||||||
|
@ -5863,6 +5950,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
||||||
/*check input values validity*/
|
/*check input values validity*/
|
||||||
if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette)
|
if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette)
|
||||||
&& (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) {
|
&& (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*/
|
state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -5883,6 +5974,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
||||||
lodepng_info_copy(&info, &state->info_png);
|
lodepng_info_copy(&info, &state->info_png);
|
||||||
if(state->encoder.auto_convert) {
|
if(state->encoder.auto_convert) {
|
||||||
LodePNGColorStats stats;
|
LodePNGColorStats stats;
|
||||||
|
unsigned allow_convert = 1;
|
||||||
lodepng_color_stats_init(&stats);
|
lodepng_color_stats_init(&stats);
|
||||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||||
if(info_png->iccp_defined &&
|
if(info_png->iccp_defined &&
|
||||||
|
@ -5904,13 +5996,74 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
||||||
/*the background chunk's color must be taken into account as well*/
|
/*the background chunk's color must be taken into account as well*/
|
||||||
unsigned r = 0, g = 0, b = 0;
|
unsigned r = 0, g = 0, b = 0;
|
||||||
LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16);
|
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);
|
state->error = lodepng_color_stats_add(&stats, r, g, b, 65535);
|
||||||
if(state->error) goto cleanup;
|
if(state->error) goto cleanup;
|
||||||
}
|
}
|
||||||
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
|
#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;
|
if(state->error) goto cleanup;
|
||||||
|
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||||
|
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
|
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||||
/*also convert the background chunk*/
|
/*also convert the background chunk*/
|
||||||
if(info_png->background_defined) {
|
if(info_png->background_defined) {
|
||||||
|
@ -5922,6 +6075,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
||||||
}
|
}
|
||||||
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
|
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||||
if(info_png->iccp_defined) {
|
if(info_png->iccp_defined) {
|
||||||
unsigned gray_icc = isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size);
|
unsigned gray_icc = isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size);
|
||||||
|
@ -5991,6 +6145,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
||||||
state->error = addChunk_cHRM(&outv, &info);
|
state->error = addChunk_cHRM(&outv, &info);
|
||||||
if(state->error) goto cleanup;
|
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*/
|
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||||
/*PLTE*/
|
/*PLTE*/
|
||||||
if(info.color.colortype == LCT_PALETTE) {
|
if(info.color.colortype == LCT_PALETTE) {
|
||||||
|
@ -6097,6 +6255,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
|
||||||
cleanup:
|
cleanup:
|
||||||
lodepng_info_cleanup(&info);
|
lodepng_info_cleanup(&info);
|
||||||
lodepng_free(data);
|
lodepng_free(data);
|
||||||
|
lodepng_color_mode_cleanup(&auto_color);
|
||||||
|
|
||||||
/*instead of cleaning the vector up, give it to the output*/
|
/*instead of cleaning the vector up, give it to the output*/
|
||||||
*out = outv.data;
|
*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
|
/*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents
|
||||||
unreasonable memory consumption when decoding due to impossibly large ICC profile*/
|
unreasonable memory consumption when decoding due to impossibly large ICC profile*/
|
||||||
case 113: return "ICC profile unreasonably large";
|
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";
|
return "unknown error code";
|
||||||
}
|
}
|
||||||
|
@ -6327,7 +6488,7 @@ unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, si
|
||||||
size_t buffersize = 0;
|
size_t buffersize = 0;
|
||||||
unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);
|
unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);
|
||||||
if(buffer) {
|
if(buffer) {
|
||||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||||
lodepng_free(buffer);
|
lodepng_free(buffer);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
|
@ -6346,7 +6507,7 @@ unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size
|
||||||
size_t buffersize = 0;
|
size_t buffersize = 0;
|
||||||
unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
|
unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
|
||||||
if(buffer) {
|
if(buffer) {
|
||||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||||
lodepng_free(buffer);
|
lodepng_free(buffer);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
|
@ -6391,7 +6552,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const
|
||||||
state.info_raw.colortype = colortype;
|
state.info_raw.colortype = colortype;
|
||||||
state.info_raw.bitdepth = bitdepth;
|
state.info_raw.bitdepth = bitdepth;
|
||||||
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
|
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);
|
lodepng_free(buffer);
|
||||||
return error;
|
return error;
|
||||||
|
@ -6409,7 +6570,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
|
||||||
unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
|
unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
|
||||||
if(buffer && !error) {
|
if(buffer && !error) {
|
||||||
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
|
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);
|
lodepng_free(buffer);
|
||||||
return error;
|
return error;
|
||||||
|
@ -6441,7 +6602,7 @@ unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsign
|
||||||
size_t buffersize;
|
size_t buffersize;
|
||||||
unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
|
unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
|
||||||
if(buffer) {
|
if(buffer) {
|
||||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||||
lodepng_free(buffer);
|
lodepng_free(buffer);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
|
@ -6461,7 +6622,7 @@ unsigned encode(std::vector<unsigned char>& out,
|
||||||
size_t buffersize;
|
size_t buffersize;
|
||||||
unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
|
unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
|
||||||
if(buffer) {
|
if(buffer) {
|
||||||
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
|
out.insert(out.end(), buffer, &buffer[buffersize]);
|
||||||
lodepng_free(buffer);
|
lodepng_free(buffer);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -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
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
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.
|
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
|
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.
|
compiler command to disable them without modifying this header, e.g.
|
||||||
-DLODEPNG_NO_COMPILE_ZLIB for gcc.
|
-DLODEPNG_NO_COMPILE_ZLIB for gcc or clang.
|
||||||
In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to
|
|
||||||
allow implementing a custom lodepng_crc32.
|
|
||||||
*/
|
*/
|
||||||
/*deflate & zlib. If disabled, you must specify alternative zlib functions in
|
/*deflate & zlib. If disabled, you must specify alternative zlib functions in
|
||||||
the custom_zlib field of the compress and decompress settings*/
|
the custom_zlib field of the compress and decompress settings*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_ZLIB
|
#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
|
#define LODEPNG_COMPILE_ZLIB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*png encoder and png decoder*/
|
/*png encoder and png decoder*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_PNG
|
#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
|
#define LODEPNG_COMPILE_PNG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*deflate&zlib decoder and png decoder*/
|
/*deflate&zlib decoder and png decoder*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_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
|
#define LODEPNG_COMPILE_DECODER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*deflate&zlib encoder and png encoder*/
|
/*deflate&zlib encoder and png encoder*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_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
|
#define LODEPNG_COMPILE_ENCODER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*the optional built in harddisk file loading and saving functions*/
|
/*the optional built in harddisk file loading and saving functions*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_DISK
|
#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
|
#define LODEPNG_COMPILE_DISK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
|
/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_ANCILLARY_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
|
#define LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*ability to convert error numerical codes to English text string*/
|
/*ability to convert error numerical codes to English text string*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
|
#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
|
#define LODEPNG_COMPILE_ERROR_TEXT
|
||||||
#endif
|
#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
|
you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
|
||||||
source files with custom allocators.*/
|
source files with custom allocators.*/
|
||||||
#ifndef LODEPNG_NO_COMPILE_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
|
#define LODEPNG_COMPILE_ALLOCATORS
|
||||||
#endif
|
#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++)*/
|
/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#ifndef LODEPNG_NO_COMPILE_CPP
|
#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
|
#define LODEPNG_COMPILE_CPP
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -374,8 +393,10 @@ typedef struct LodePNGColorMode {
|
||||||
|
|
||||||
The alpha channels must be set as well, set them to 255 for opaque images.
|
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
|
When decoding, with the default settings you can ignore this palette, since
|
||||||
fills the palette colors in the pixels of the raw RGBA output.
|
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.
|
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.
|
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
|
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
|
When decoding, you may get these in a different color mode than the one you requested
|
||||||
for the raw pixels.
|
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
|
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
|
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)*/
|
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
|
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
|
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 char* iccp_profile;
|
||||||
unsigned iccp_profile_size; /* The size of iccp_profile in bytes */
|
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 */
|
/* End of color profile related chunks */
|
||||||
|
|
||||||
|
|
||||||
|
@ -770,7 +832,11 @@ typedef struct LodePNGEncoderSettings {
|
||||||
const unsigned char* predefined_filters;
|
const unsigned char* predefined_filters;
|
||||||
|
|
||||||
/*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).
|
/*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;
|
unsigned force_palette;
|
||||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||||
/*add LodePNG identifier and version as a text chunk, for debugging*/
|
/*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*/
|
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it
|
Reads one metadata chunk (other than IHDR, which is handled by lodepng_inspect)
|
||||||
read in the state. Returns error code on failure.
|
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
|
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
|
to find the desired chunk type, and if non null use lodepng_inspect_chunk (with
|
||||||
chunk_pointer - start_of_file as pos).
|
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
|
[.] 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] converting color to 16-bit per channel types
|
||||||
[X] support color profile chunk types (but never let them touch RGB values by default)
|
[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
|
[ ] make sure encoder generates no chunks with size > (2^31)-1
|
||||||
[ ] partial decoding (stream processing)
|
[ ] partial decoding (stream processing)
|
||||||
[X] let the "isFullyOpaque" function check color keys and transparent palettes too
|
[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
|
gAMA: RGB gamma correction
|
||||||
iCCP: ICC color profile
|
iCCP: ICC color profile
|
||||||
sRGB: rendering intent
|
sRGB: rendering intent
|
||||||
|
sBIT: significant bits
|
||||||
|
|
||||||
1.2. features not supported
|
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.
|
*) 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.
|
*) 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:
|
*) The hIST and sPLT public chunks are not (yet) supported but treated as unknown chunks
|
||||||
sBIT
|
|
||||||
hIST
|
|
||||||
sPLT
|
|
||||||
|
|
||||||
|
|
||||||
2. C and C++ version
|
2. C and C++ version
|
||||||
|
@ -1845,6 +1909,8 @@ symbol.
|
||||||
Not all changes are listed here, the commit history in github lists more:
|
Not all changes are listed here, the commit history in github lists more:
|
||||||
https://github.com/lvandeve/lodepng
|
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
|
*) 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
|
wide-character filenames (support for this is not planned, opening files is
|
||||||
not the core part of PNG decoding/decoding and is platform dependent).
|
not the core part of PNG decoding/decoding and is platform dependent).
|
||||||
|
@ -2015,5 +2081,5 @@ Domain: gmail dot com.
|
||||||
Account: lode dot vandevenne.
|
Account: lode dot vandevenne.
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2005-2021 Lode Vandevenne
|
Copyright (c) 2005-2022 Lode Vandevenne
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1161,8 +1161,11 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate)
|
||||||
case 0x15: // RBR MSB
|
case 0x15: // RBR MSB
|
||||||
if (bUpdate)
|
if (bUpdate)
|
||||||
{
|
{
|
||||||
Chipset.IORam[RCS] &= ~RBF;
|
|
||||||
*a = Chipset.IORam[d]; // return RBR value
|
*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
|
UpdateUSRQ(); // update USRQ
|
||||||
rbr_acc = TRUE; // search for new RBR value
|
rbr_acc = TRUE; // search for new RBR value
|
||||||
#if defined DEBUG_SERIAL
|
#if defined DEBUG_SERIAL
|
||||||
|
@ -1614,13 +1617,13 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
|
||||||
// 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only)
|
// 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
|
// 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event
|
||||||
case 0x1A:
|
case 0x1A:
|
||||||
// COM port open and EIRU bit changed
|
// EIRU bit changed
|
||||||
if (bCommInit && ((c^Chipset.IORam[d]) & EIRU) != 0)
|
if (((c^Chipset.IORam[d]) & EIRU) != 0)
|
||||||
{
|
{
|
||||||
// save new value for COM open
|
// save new value for COM open
|
||||||
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
|
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
|
||||||
// reopen COM port with new setting
|
// reopen COM port with new setting
|
||||||
bCommInit = CommOpen(szSerialWire,szSerialIr);
|
CommOpen(szSerialWire,szSerialIr);
|
||||||
}
|
}
|
||||||
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
|
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
|
||||||
#if defined DEBUG_SERIAL
|
#if defined DEBUG_SERIAL
|
||||||
|
|
|
@ -84,7 +84,7 @@ VOID MruCleanup(VOID)
|
||||||
{
|
{
|
||||||
for (i = 0; i < nEntry; ++i) // cleanup each entry
|
for (i = 0; i < nEntry; ++i) // cleanup each entry
|
||||||
{
|
{
|
||||||
if (ppszFiles[i] != NULL)
|
if (ppszFiles[i] != NULL) // valid entry
|
||||||
free(ppszFiles[i]); // cleanup entry
|
free(ppszFiles[i]); // cleanup entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ VOID MruAdd(LPCTSTR lpszEntry)
|
||||||
for (i = 0; i < nEntry; ++i)
|
for (i = 0; i < nEntry; ++i)
|
||||||
{
|
{
|
||||||
// already in table -> quit
|
// already in table -> quit
|
||||||
if ( ppszFiles[i] != NULL
|
if ( ppszFiles[i] != NULL // valid entry
|
||||||
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
|
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
|
||||||
{
|
{
|
||||||
MruMoveTop(i); // move to top and update menu
|
MruMoveTop(i); // move to top and update menu
|
||||||
|
@ -120,7 +120,7 @@ VOID MruAdd(LPCTSTR lpszEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = nEntry - 1; // last index
|
i = nEntry - 1; // last index
|
||||||
if (ppszFiles[i] != NULL)
|
if (ppszFiles[i] != NULL) // valid entry
|
||||||
free(ppszFiles[i]); // free oldest entry
|
free(ppszFiles[i]); // free oldest entry
|
||||||
|
|
||||||
for (; i > 0; --i) // move old entries 1 line down
|
for (; i > 0; --i) // move old entries 1 line down
|
||||||
|
@ -173,16 +173,43 @@ UINT MruEntries(VOID)
|
||||||
return nEntry;
|
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
|
// MRU initialized and index inside valid range
|
||||||
if (ppszFiles != NULL && nIndex < nEntry)
|
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)
|
VOID MruUpdateMenu(HMENU hMenu)
|
||||||
|
@ -312,7 +339,7 @@ VOID MruWriteList(VOID)
|
||||||
{
|
{
|
||||||
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
||||||
wsprintf(szItemname,_T("File%d"),i+1);
|
wsprintf(szItemname,_T("File%d"),i+1);
|
||||||
if (ppszFiles[i] != NULL)
|
if (ppszFiles[i] != NULL) // valid entry
|
||||||
{
|
{
|
||||||
WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
|
WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
|
||||||
}
|
}
|
||||||
|
@ -338,7 +365,7 @@ VOID MruReadList(VOID)
|
||||||
wsprintf(szItemname,_T("File%d"),i+1);
|
wsprintf(szItemname,_T("File%d"),i+1);
|
||||||
ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename));
|
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
|
free(ppszFiles[i]); // free entry
|
||||||
ppszFiles[i] = NULL; // clear last line
|
ppszFiles[i] = NULL; // clear last line
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier
|
#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier
|
||||||
|
#define __unaligned
|
||||||
#define SetWindowLongPtr SetWindowLong
|
#define SetWindowLongPtr SetWindowLong
|
||||||
#define GetWindowLongPtr GetWindowLong
|
#define GetWindowLongPtr GetWindowLong
|
||||||
#define SetClassLongPtr SetClassLong
|
#define SetClassLongPtr SetClassLong
|
||||||
|
|
|
@ -93,6 +93,11 @@ static DWORD WINAPI EventThread(LPVOID pParam)
|
||||||
UNREFERENCED_PARAMETER(pParam);
|
UNREFERENCED_PARAMETER(pParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL CommIsOpen(VOID)
|
||||||
|
{
|
||||||
|
return hComm != NULL; // have COM port handle
|
||||||
|
}
|
||||||
|
|
||||||
BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
|
BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
|
||||||
{
|
{
|
||||||
COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L };
|
COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L };
|
||||||
|
@ -353,7 +358,7 @@ VOID CommReceive(VOID)
|
||||||
// reject reading if com port is closed and not whole operation
|
// reject reading if com port is closed and not whole operation
|
||||||
if (hComm && dwBytesRead == 0L) // com port open and buffer empty
|
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;
|
dwBytesRead = 0L;
|
||||||
else // bytes received
|
else // bytes received
|
||||||
nRp = 0; // reset read pointer
|
nRp = 0; // reset read pointer
|
||||||
|
|
|
@ -42,6 +42,7 @@ BOOL settingsPort2en;
|
||||||
BOOL settingsPort2wr;
|
BOOL settingsPort2wr;
|
||||||
BOOL soundAvailable = FALSE;
|
BOOL soundAvailable = FALSE;
|
||||||
BOOL soundEnabled = FALSE;
|
BOOL soundEnabled = FALSE;
|
||||||
|
BOOL serialPortSlowDown = FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1005,6 +1006,9 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onViewCopy(JNIEnv
|
||||||
AndroidBitmap_unlockPixels(env, bitmapScreen);
|
AndroidBitmap_unlockPixels(env, bitmapScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onStackCopyVisible(JNIEnv *env, jobject thisz) {
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onStackCopy(JNIEnv *env, jobject thisz) {
|
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onStackCopy(JNIEnv *env, jobject thisz) {
|
||||||
OnStackCopy();
|
OnStackCopy();
|
||||||
}
|
}
|
||||||
|
@ -1297,18 +1301,20 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setConfiguration(J
|
||||||
const char * newSerialWire = _tcscmp(_T("0000:0000,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
const char * newSerialWire = _tcscmp(_T("0000:0000,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
||||||
BOOL serialWireChanged = _tcscmp(szSerialWire, newSerialWire) != 0;
|
BOOL serialWireChanged = _tcscmp(szSerialWire, newSerialWire) != 0;
|
||||||
_tcsncpy(szSerialWire, newSerialWire, sizeof(szSerialWire));
|
_tcsncpy(szSerialWire, newSerialWire, sizeof(szSerialWire));
|
||||||
if(bCommInit && serialWireChanged) {
|
if(CommIsOpen() && serialWireChanged) {
|
||||||
// Not the right thread, but it seems to work.
|
// Not the right thread, but it seems to work.
|
||||||
bCommInit = CommOpen(szSerialWire, szSerialIr);
|
CommOpen(szSerialWire, szSerialIr);
|
||||||
}
|
}
|
||||||
} else if(_tcscmp(_T("settings_serial_ports_ir"), configKey) == 0) {
|
} else if(_tcscmp(_T("settings_serial_ports_ir"), configKey) == 0) {
|
||||||
const char * newSerialIr = _tcscmp(_T("0000:0000,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
const char * newSerialIr = _tcscmp(_T("0000:0000,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
||||||
BOOL serialIrChanged = _tcscmp(szSerialIr, newSerialIr) != 0;
|
BOOL serialIrChanged = _tcscmp(szSerialIr, newSerialIr) != 0;
|
||||||
_tcsncpy(szSerialIr, newSerialIr, sizeof(szSerialIr));
|
_tcsncpy(szSerialIr, newSerialIr, sizeof(szSerialIr));
|
||||||
if(bCommInit && serialIrChanged) {
|
if(CommIsOpen() && serialIrChanged) {
|
||||||
// Not the right thread, but it seems to work.
|
// Not the right thread, but it seems to work.
|
||||||
bCommInit = CommOpen(szSerialWire, szSerialIr);
|
CommOpen(szSerialWire, szSerialIr);
|
||||||
}
|
}
|
||||||
|
} else if(_tcscmp(_T("settings_serial_slowdown"), configKey) == 0) {
|
||||||
|
serialPortSlowDown = (BOOL)intValue1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(configKey)
|
if(configKey)
|
||||||
|
|
|
@ -341,6 +341,7 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,LPDWO
|
||||||
SERIAL_LOGD("WriteFile(hFile: %p, lpBuffer: 0x%08x, nNumberOfBytesToWrite: %d) -> %d bytes\n%s", hFile, lpBuffer, nNumberOfBytesToWrite, writenByteCount, hexAsciiDump);
|
SERIAL_LOGD("WriteFile(hFile: %p, lpBuffer: 0x%08x, nNumberOfBytesToWrite: %d) -> %d bytes\n%s", hFile, lpBuffer, nNumberOfBytesToWrite, writenByteCount, hexAsciiDump);
|
||||||
free(hexAsciiDump);
|
free(hexAsciiDump);
|
||||||
#endif
|
#endif
|
||||||
|
if(serialPortSlowDown)
|
||||||
Sleep(4); // Seems to be needed else the kermit packet does not fully reach the genuine calculator.
|
Sleep(4); // Seems to be needed else the kermit packet does not fully reach the genuine calculator.
|
||||||
if(lpNumberOfBytesWritten)
|
if(lpNumberOfBytesWritten)
|
||||||
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
||||||
|
@ -3484,3 +3485,9 @@ int win32_select(int __fd_count, fd_set* __read_fds, fd_set* __write_fds, fd_set
|
||||||
}
|
}
|
||||||
return select(__fd_count, __read_fds, __write_fds, __exception_fds, __timeout);
|
return select(__fd_count, __read_fds, __write_fds, __exception_fds, __timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int win32_ioctlsocket(SOCKET s, long cmd, u_long FAR * argp) {
|
||||||
|
//TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <sys/select.h>
|
||||||
#include <android/bitmap.h>
|
#include <android/bitmap.h>
|
||||||
#include <android/asset_manager.h>
|
#include <android/asset_manager.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _MSC_VER 1914
|
#define _MSC_VER 1914
|
||||||
|
#define __unaligned
|
||||||
#define GetWindowLongPtr GetWindowLong
|
#define GetWindowLongPtr GetWindowLong
|
||||||
|
|
||||||
|
|
||||||
|
@ -1370,6 +1372,7 @@ extern BOOL SetCommState(HANDLE hFile, LPDCB lpDCB);
|
||||||
extern BOOL PurgeComm(HANDLE hFile, DWORD dwFlags);
|
extern BOOL PurgeComm(HANDLE hFile, DWORD dwFlags);
|
||||||
extern BOOL SetCommBreak(HANDLE hFile);
|
extern BOOL SetCommBreak(HANDLE hFile);
|
||||||
extern BOOL ClearCommBreak(HANDLE hFile);
|
extern BOOL ClearCommBreak(HANDLE hFile);
|
||||||
|
extern BOOL serialPortSlowDown;
|
||||||
|
|
||||||
// TCP
|
// TCP
|
||||||
|
|
||||||
|
@ -1378,6 +1381,7 @@ typedef int SOCKET;
|
||||||
#define SOCKET_ERROR (-1)
|
#define SOCKET_ERROR (-1)
|
||||||
|
|
||||||
#define WSAEINTR 10004L
|
#define WSAEINTR 10004L
|
||||||
|
#define WSAEWOULDBLOCK 10035L
|
||||||
extern int WSAGetLastError();
|
extern int WSAGetLastError();
|
||||||
|
|
||||||
typedef struct WSAData {
|
typedef struct WSAData {
|
||||||
|
|
|
@ -66,6 +66,7 @@ public class NativeLib {
|
||||||
public static native String[] getObjectsToSave();
|
public static native String[] getObjectsToSave();
|
||||||
public static native int onObjectSave(String filename, boolean[] objectsToSaveItemChecked);
|
public static native int onObjectSave(String filename, boolean[] objectsToSaveItemChecked);
|
||||||
public static native void onViewCopy(Bitmap bitmapScreen);
|
public static native void onViewCopy(Bitmap bitmapScreen);
|
||||||
|
public static native void onStackCopyVisible();
|
||||||
public static native void onStackCopy();
|
public static native void onStackCopy();
|
||||||
public static native void onStackPaste();
|
public static native void onStackPaste();
|
||||||
public static native void onViewReset();
|
public static native void onViewReset();
|
||||||
|
|
|
@ -370,6 +370,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
OnViewCopyFullscreen();
|
OnViewCopyFullscreen();
|
||||||
} else if (id == R.id.nav_copy_screen) {
|
} else if (id == R.id.nav_copy_screen) {
|
||||||
OnViewCopy();
|
OnViewCopy();
|
||||||
|
// } else if (id == R.id.nav_copy_stack_visible) {
|
||||||
|
// OnStackCopyVisible();
|
||||||
} else if (id == R.id.nav_copy_stack) {
|
} else if (id == R.id.nav_copy_stack) {
|
||||||
OnStackCopy();
|
OnStackCopy();
|
||||||
} else if (id == R.id.nav_paste_stack) {
|
} else if (id == R.id.nav_paste_stack) {
|
||||||
|
@ -446,6 +448,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
menu.findItem(R.id.nav_load_object).setEnabled(uRun && bObjectEnable);
|
menu.findItem(R.id.nav_load_object).setEnabled(uRun && bObjectEnable);
|
||||||
menu.findItem(R.id.nav_save_object).setEnabled(uRun && bObjectEnable);
|
menu.findItem(R.id.nav_save_object).setEnabled(uRun && bObjectEnable);
|
||||||
menu.findItem(R.id.nav_copy_screen).setEnabled(uRun);
|
menu.findItem(R.id.nav_copy_screen).setEnabled(uRun);
|
||||||
|
// menu.findItem(R.id.nav_copy_stack_visible).setEnabled(uRun && bBertOrSaca); // HDW_SACA || HDW_BERT)
|
||||||
menu.findItem(R.id.nav_copy_stack).setEnabled(uRun && bStackCEnable);
|
menu.findItem(R.id.nav_copy_stack).setEnabled(uRun && bStackCEnable);
|
||||||
menu.findItem(R.id.nav_paste_stack).setEnabled(uRun && bStackPEnable);
|
menu.findItem(R.id.nav_paste_stack).setEnabled(uRun && bStackPEnable);
|
||||||
menu.findItem(R.id.nav_reset_calculator).setEnabled(uRun);
|
menu.findItem(R.id.nav_reset_calculator).setEnabled(uRun);
|
||||||
|
@ -929,6 +932,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
showAlert(e.getMessage());
|
showAlert(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void OnStackCopyVisible() {
|
||||||
|
NativeLib.onStackCopyVisible();
|
||||||
|
}
|
||||||
private void OnStackCopy() {
|
private void OnStackCopy() {
|
||||||
NativeLib.onStackCopy();
|
NativeLib.onStackCopy();
|
||||||
}
|
}
|
||||||
|
@ -987,7 +993,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
} else
|
} else
|
||||||
kmlScriptsForCurrentModel = kmlScripts;
|
kmlScriptsForCurrentModel = kmlScripts;
|
||||||
|
|
||||||
boolean showDefaultKMLScriptFolderItem = !kmlFolderUseDefault && (getPackageName().contains("org.emulator.forty.eight") || getPackageName().contains("org.emulator.forty.two"));
|
boolean showDefaultKMLScriptFolderItem = !kmlFolderUseDefault && (
|
||||||
|
getPackageName().contains("org.emulator.forty.eight")
|
||||||
|
|| getPackageName().contains("org.emulator.forty.two")
|
||||||
|
|| getPackageName().contains("org.emulator.twenty.eight"));
|
||||||
int lastIndex = kmlScriptsForCurrentModel.size();
|
int lastIndex = kmlScriptsForCurrentModel.size();
|
||||||
String[] kmlScriptTitles = new String[lastIndex + (showDefaultKMLScriptFolderItem ? 2 : 1)];
|
String[] kmlScriptTitles = new String[lastIndex + (showDefaultKMLScriptFolderItem ? 2 : 1)];
|
||||||
for (int i = 0; i < kmlScriptsForCurrentModel.size(); i++)
|
for (int i = 0; i < kmlScriptsForCurrentModel.size(); i++)
|
||||||
|
@ -2201,7 +2210,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
"settings_printer_model", "settings_macro",
|
"settings_printer_model", "settings_macro",
|
||||||
"settings_kml", "settings_port1", "settings_port2",
|
"settings_kml", "settings_port1", "settings_port2",
|
||||||
"settings_flash_port2",
|
"settings_flash_port2",
|
||||||
"settings_serial_ports_wire", "settings_serial_ports_ir" };
|
"settings_serial_ports_wire", "settings_serial_ports_ir", "settings_serial_slowdown" };
|
||||||
for (String settingKey : settingKeys)
|
for (String settingKey : settingKeys)
|
||||||
updateFromPreferences(settingKey, false);
|
updateFromPreferences(settingKey, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2331,6 +2340,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
NativeLib.setConfiguration("settings_serial_ports_ir", isDynamicValue, 0, 0,
|
NativeLib.setConfiguration("settings_serial_ports_ir", isDynamicValue, 0, 0,
|
||||||
DevicesFragment.SerialConnectParameters.fromSettingsString(settings.getString("settings_serial_ports_ir", "")).toWin32String());
|
DevicesFragment.SerialConnectParameters.fromSettingsString(settings.getString("settings_serial_ports_ir", "")).toWin32String());
|
||||||
break;
|
break;
|
||||||
|
case "settings_serial_slowdown":
|
||||||
|
NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,10 @@
|
||||||
android:id="@+id/nav_copy_screen"
|
android:id="@+id/nav_copy_screen"
|
||||||
android:icon="@drawable/ic_menu_share"
|
android:icon="@drawable/ic_menu_share"
|
||||||
android:title="@string/nav_copy_screen" />
|
android:title="@string/nav_copy_screen" />
|
||||||
|
<!--<item
|
||||||
|
android:id="@+id/nav_copy_stack_visible"
|
||||||
|
android:icon="@drawable/ic_filter_none_black_24dp"
|
||||||
|
android:title="@string/nav_copy_stack_visible" /> -->
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_copy_stack"
|
android:id="@+id/nav_copy_stack"
|
||||||
android:icon="@drawable/ic_filter_none_black_24dp"
|
android:icon="@drawable/ic_filter_none_black_24dp"
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<string name="nav_save_object">Save Object...</string>
|
<string name="nav_save_object">Save Object...</string>
|
||||||
<string name="nav_copy_screen">Copy Screen</string>
|
<string name="nav_copy_screen">Copy Screen</string>
|
||||||
<string name="nav_copy_fullscreen">Copy Fullscreen</string>
|
<string name="nav_copy_fullscreen">Copy Fullscreen</string>
|
||||||
|
<string name="nav_copy_stack_visible">Copy Visible Stack</string>
|
||||||
<string name="nav_copy_stack">Copy Stack</string>
|
<string name="nav_copy_stack">Copy Stack</string>
|
||||||
<string name="nav_recents">Recent</string>
|
<string name="nav_recents">Recent</string>
|
||||||
<string name="nav_edit">Edit</string>
|
<string name="nav_edit">Edit</string>
|
||||||
|
@ -223,5 +224,6 @@
|
||||||
<string name="settings_category_serial_ports_title">Serial Ports (Please allow USB OTG)</string>
|
<string name="settings_category_serial_ports_title">Serial Ports (Please allow USB OTG)</string>
|
||||||
<string name="settings_serial_ports_wire_title">Wire</string>
|
<string name="settings_serial_ports_wire_title">Wire</string>
|
||||||
<string name="settings_serial_ports_ir_title">Infrared (2400 baud only)</string>
|
<string name="settings_serial_ports_ir_title">Infrared (2400 baud only)</string>
|
||||||
|
<string name="settings_serial_slowdown">Slowdown transmission (prevent errors with 9600 baud)</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/settings_category_general_title">
|
<PreferenceCategory android:title="@string/settings_category_general_title">
|
||||||
|
@ -187,6 +188,11 @@
|
||||||
android:title="@string/settings_serial_ports_ir_title"
|
android:title="@string/settings_serial_ports_ir_title"
|
||||||
android:summary=""
|
android:summary=""
|
||||||
/>
|
/>
|
||||||
|
<!-- <SwitchPreference-->
|
||||||
|
<!-- android:defaultValue="false"-->
|
||||||
|
<!-- android:key="settings_serial_slowdown"-->
|
||||||
|
<!-- android:title="@string/settings_serial_slowdown"-->
|
||||||
|
<!-- />-->
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.1.2'
|
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||||
|
|
Loading…
Reference in a new issue