2022-07-31: Updated to version 64

Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
Gwenhael Le Moine 2024-03-20 07:46:29 +01:00
parent 9fb7be9e3d
commit 0218951158
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
17 changed files with 1011 additions and 284 deletions

BIN
Emu48.dll

Binary file not shown.

BIN
Emu48.exe

Binary file not shown.

170
Emu48.htm
View file

@ -34,7 +34,8 @@ h3 { color:red; font-size:1.1em; }
<div id="navi">
<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="#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="#s5">5. How to Start</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>
</span></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="#s15">15. License</a></p>
<p><a class="nav1" href="#s14">14. License</a></p>
</div>
<div id="main">
<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
and HP49G calculator hardware. These calculators are based on the
1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
@ -127,73 +127,97 @@ h3 { color:red; font-size:1.1em; }
in the destination file with zeros. Final notice, the convert
utility shows the CRC result after the file convert and a passed
ROM CRC test does <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>
<ul>
<li>HP38
<p>To upload the ROM of your HP38G, you will need a special aplet
called <a href="http://www.hpcalc.org/details.php?id=633">&quot;ROM UPLOAD&quot;</a>.
Once you've uploaded the ROM, you have to convert it using the
Convert utility.</p>
<p>To do that, start a Command Prompt while running Windows, and
type:</p>
<blockquote>Convert &lt;rom-file&gt; ROM.38G</blockquote>
<p>Where &lt;rom-file&gt; is the path to your ROM image. This will
create a file named ROM.38G. This tool will also check its validity.
</p></li>
<li>HP39/40
<p>To upload the ROM of your HP39G/HP40G, you will need a special aplet
called <a href="http://hp.giesselink.com/emu48.htm">&quot;ROM UPLOAD&quot;</a>.
Once you've uploaded the ROM, you have to convert it using the Rom2emu utility.
</p>
<p>To do that, start a Command Prompt while running Windows, and
type:</p>
<blockquote>Rom2emu &lt;rom-file&gt; ROM.39G</blockquote>
<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>.
</p></li>
<li>HP48
<p>If you have already used another HP48 emulator, you can convert
the ROM using the Convert utility.
</p>
<p>To do that, start a Command Prompt while running Windows, and
type:</p>
<blockquote>Convert &lt;rom-file&gt; ROM.48G</blockquote>
<p>or</p>
<blockquote>Convert &lt;rom-file&gt; ROM.48S</blockquote>
<p>Where &lt;rom-file&gt; is the path to your old ROM image. This
will create a file named ROM.48G or ROM.48S, depending on the version
you own. This tool should be able to read any style of ROM image, and
will also check its validity. Note that if you run it with only one
parameter, no file will be written, but it will still check the
validity of the ROM.</p>
<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
ROMDump Wizard V1.x, which will almost automatically get the ROM from
your HP48. After the download you may have to convert your dump with
the CONVERT utility into the Emu48 format.</p>
<p>You can find the latest version of the ROM dump programs on:</p>
<blockquote>
ROMUPL.BIN <a href="http://www.hpcalc.org/details.php?id=3686">
http://www.hpcalc.org/details.php?id=3686</a><br>
ROMDump Wizard
<a href="http://hp.giesselink.com/emu48.htm">
http://hp.giesselink.com/emu48.htm</a>
</blockquote></li>
<li>HP49G
<p>There's no ROM download program available so far. But you can
create a ROM image with the
<a href="http://hp.giesselink.com/emu48.htm">UPD49ROM tool</a>
and a <a href="http://www.hpcalc.org/hp49/pc/rom/">
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>
</p>
<p>To create a HP49G ROM image file, start a Command Prompt while
running Windows, and type:</p>
<blockquote>UPD49ROM -f hp49119-6.flash ROM.49G</blockquote>
<p>This will create a HP49G ROM image file with an empty User
Port 2.</p></li>
</ul>
<p>The general syntax of the convert utility is:</p>
<blockquote>Convert [-p] &lt;old-rom-dump&gt; [&lt;new-rom-dump&gt;]</blockquote>
<p>where:</p>
<blockquote>Convert &lt;old-rom-dump&gt;</blockquote>
<p>check if &lt;old-rom-dump&gt; 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 &lt;old-rom-dump&gt; &lt;new-rom-dump&gt;</blockquote>
<p>convert the file &lt;old-rom-dump&gt; into the <u>unpacked</u>
ROM image file &lt;new-rom-dump&gt; valid for use in Emu48.
</p>
<p>where:</p>
<blockquote>Convert -p &lt;old-rom-dump&gt; &lt;new-rom-dump&gt;</blockquote>
<p>convert the file &lt;old-rom-dump&gt; into the <u>packed</u>
ROM image file &lt;new-rom-dump&gt; valid for use in Emu48.
</p>
<h2><a name=ss3.1>3.1 Creation examples</a></h2>
<ul>
<li>HP38
<p>To upload the ROM of your HP38G, you will need a special aplet
called <a href="http://www.hpcalc.org/details.php?id=633">&quot;ROM UPLOAD&quot;</a>.
Once you've uploaded the ROM, you have to convert it using the
Convert utility.</p>
<p>To do that, start a Command Prompt while running Windows, and
type:</p>
<blockquote>Convert -p &lt;rom-file&gt; ROM.38G</blockquote>
<p>Where &lt;rom-file&gt; is the path to your ROM image. This will
create a packed file named ROM.38G. This tool will also check its validity.
</p></li>
<li>HP39/40
<p>To upload the ROM of your HP39G/HP40G, you will need a special aplet
called <a href="https://hp.giesselink.com/emu48.htm">&quot;ROM UPLOAD&quot;</a>.
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>To do that, start a Command Prompt while running Windows, and
type:</p>
<blockquote>Rom2emu &lt;rom-file&gt; ROM.39G</blockquote>
<p>or</p>
<blockquote>rename &lt;rom-file&gt; ROM.39G</blockquote>
<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>.
</p></li>
<li>HP48
<p>If you have already used another HP48 emulator, you can convert
the ROM using the Convert utility.
</p>
<p>To do that, start a Command Prompt while running Windows, and
type:</p>
<blockquote>Convert &lt;rom-file&gt; ROM.48G</blockquote>
<p>or</p>
<blockquote>Convert &lt;rom-file&gt; ROM.48S</blockquote>
<p>Where &lt;rom-file&gt; is the path to your old ROM image. This
will create a file named ROM.48G or ROM.48S, depending on the
version you own. This tool should be able to read any style of
ROM image, and will also check its validity. Note that if you run
it with only one parameter, no file will be written, but it will
still check the validity of the ROM.</p>
<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
ROMDump Wizard V1.x, which will almost automatically get the ROM
from your HP48. After the download you may have to convert your
dump with the CONVERT utility into the Emu48 format.</p>
<p>You can find the latest version of the ROM dump programs on:</p>
<blockquote>
ROMUPL.BIN <a href="http://www.hpcalc.org/details.php?id=3686">
http://www.hpcalc.org/details.php?id=3686</a><br>
ROMDump Wizard
<a href="https://hp.giesselink.com/emu48.htm">
https://hp.giesselink.com/emu48.htm</a>
</blockquote></li>
<li>HP49G
<p>There's no ROM download program available so far. But you can
create a ROM image with the
<a href="https://hp.giesselink.com/emu48.htm">UPD49ROM tool</a>
and a <a href="http://www.hpcalc.org/hp49/pc/rom/">
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>
</p>
<p>To create a HP49G ROM image file, start a Command Prompt while
running Windows, and type:</p>
<blockquote>UPD49ROM -f hp49119-6.flash ROM.49G</blockquote>
<p>This will create a HP49G ROM image file with an empty User
Port 2.</p></li>
</ul>
<h1><a name=s4>4. Installation</a></h1>
<p>To install Emu48 you may use the installer package which contain,
among the binaries, some HP48 KML scripts or just unzip the emulator
@ -239,7 +263,7 @@ h3 { color:red; font-size:1.1em; }
<p>If you want other great scripts, visit Rechlin's great HP archive
<a href="http://www.hpcalc.org/"></a></p>
<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>
<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
@ -462,7 +486,7 @@ h3 { color:red; font-size:1.1em; }
simulation. The data transfer to the printer simulator is done over UDP.
In this section you can the define the IPv4 address and the port the
printer simulator is listening. A suitable HP82240B printer simulation can
be found <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>
<ul>
<li><i>Wire</i>
@ -651,7 +675,7 @@ h3 { color:red; font-size:1.1em; }
Cyrille de Brebisson of Hewlett-Packard.</p>
<h1><a name=s15>15. License</a></h1>
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
Copyright (C) 2021 Christoph Gie&szlig;elink</p>
Copyright (C) 2022 Christoph Gie&szlig;elink</p>
<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
Software Foundation; either version 2 of the License, or (at your option)

View file

@ -1,4 +1,4 @@
Service Pack 63+ based on Emu48 Service Pack 64
Service Pack 64+ based on Emu48 Service Pack 65
See CHANGES.TXT in Emu48 for full history.
Only changes specifically made to Emu48+ are shown below.

View file

@ -13,7 +13,7 @@
#include "kml.h"
#include "debugger.h"
#define VERSION "1.63+"
#define VERSION "1.64+"
#ifdef _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
SetCommList(hDlg,szSerialWire,szSerialIr);
if (bCommInit) // disable when port open
if (CommIsOpen()) // disable when port open
{
EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE);
EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE);
@ -768,7 +768,10 @@ static UINT SaveChanges(BOOL bAuto)
if (GetSaveAsFilename())
{
if (SaveDocumentAs(szBufferFilename))
{
MruAdd(szBufferFilename);
return IDYES;
}
else
return IDCANCEL;
}
@ -776,6 +779,7 @@ static UINT SaveChanges(BOOL bAuto)
}
SaveDocument();
MruAdd(szCurrentFilename);
return IDYES;
}
@ -1056,25 +1060,32 @@ cancel:
//
static LRESULT OnFileMruOpen(UINT wID)
{
LPCTSTR lpszFilename;
TCHAR szFilename[MAX_PATH];
wID -= ID_FILE_MRU_FILE1; // zero based MRU index
lpszFilename = MruFilename(wID); // full filename from MRU list
if (lpszFilename == NULL) return 0; // MRU slot not filled
// full filename from MRU list
MruFilename(wID,szFilename,ARRAYSIZEOF(szFilename));
if (*szFilename == 0) return 0; // MRU slot not filled
if (bDocumentAvail)
{
SwitchToState(SM_INVALID);
// saving may change MRU index and destroy lpszFilename pointer content
if (IDCANCEL == SaveChanges(bAutoSave))
goto cancel;
}
if (!OpenDocument(lpszFilename)) // document loading failed
if (!OpenDocument(szFilename)) // document loading failed
{
MruRemove(wID); // entry not valid any more
wID = MruID(szFilename); // get actual MRU ID after saving
if (wID != (UINT) -1) // entry still in MRU list
{
MruRemove(wID); // entry not valid any more
}
}
else
{
MruMoveTop(wID); // move entry to top of MRU list
MruAdd(szFilename); // add entry to top of MRU list
}
cancel:
if (pbyRom) SwitchToState(SM_RUN);

View file

@ -133,7 +133,8 @@ extern VOID MruAdd(LPCTSTR lpszEntry);
extern VOID MruRemove(UINT nIndex);
extern VOID MruMoveTop(UINT nIndex);
extern UINT MruEntries(VOID);
extern LPCTSTR MruFilename(UINT nIndex);
extern UINT MruID(LPCTSTR lpszEntry);
extern VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize);
extern VOID MruUpdateMenu(HMENU hMenu);
extern VOID MruWriteList(VOID);
extern VOID MruReadList(VOID);
@ -193,7 +194,6 @@ extern BOOL bRealSpeed;
extern BOOL bKeySlow;
extern BOOL bSoundSlow;
extern UINT nOpcSlow;
extern BOOL bCommInit;
extern CHIPSET Chipset;
extern TCHAR szSerialWire[16];
extern TCHAR szSerialIr[16];
@ -412,6 +412,7 @@ extern LPCTSTR RplGetName(DWORD dwAddr);
extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr);
// Serial.c
extern BOOL CommIsOpen(VOID);
extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort);
extern VOID CommClose(VOID);
extern VOID CommSetBaud(VOID);

View file

@ -303,7 +303,7 @@ FONT 8, "MS Sans Serif"
BEGIN
ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE
LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP
LTEXT "Copyright © 2021 Christoph Gießelink && Sébastien Carlier",
LTEXT "Copyright © 2022 Christoph Gießelink && Sébastien Carlier",
IDC_STATIC,29,18,181,8
DEFPUSHBUTTON "OK",IDOK,215,12,39,14
EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL |
@ -723,8 +723,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,6,3,0
PRODUCTVERSION 1,6,3,0
FILEVERSION 1,6,4,0
PRODUCTVERSION 1,6,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -741,12 +741,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
VALUE "FileDescription", "HP38/39/40/48/49/50 Emulator\0"
VALUE "FileVersion", "1, 6, 3, 0\0"
VALUE "FileVersion", "1, 6, 4, 0\0"
VALUE "InternalName", "Emu48+\0"
VALUE "LegalCopyright", "Copyright © 2021\0"
VALUE "LegalCopyright", "Copyright © 2022\0"
VALUE "OriginalFilename", "Emu48.exe\0"
VALUE "ProductName", "Emu48+\0"
VALUE "ProductVersion", "1, 6, 3, 0\0"
VALUE "ProductVersion", "1, 6, 4, 0\0"
END
END
BLOCK "VarFileInfo"

View file

@ -22,7 +22,6 @@ BOOL bRealSpeed = FALSE;
BOOL bKeySlow = FALSE; // slow down for key emulation
BOOL bSoundSlow = FALSE; // slow down for sound emulation
UINT nOpcSlow = 0; // no. of opcodes to slow down
BOOL bCommInit = FALSE; // COM port not open
CHIPSET Chipset;
@ -353,16 +352,15 @@ static __inline VOID SetT2Cycles(VOID) // set device specific cpu cycles in int
VOID CheckSerial(VOID)
{
// COM port closed and serial on
if (bCommInit == FALSE && (Chipset.IORam[IOC] & SON) != 0)
if (CommIsOpen() == FALSE && (Chipset.IORam[IOC] & SON) != 0)
{
bCommInit = CommOpen(szSerialWire,szSerialIr); // open COM ports
CommOpen(szSerialWire,szSerialIr); // open COM ports
}
// COM port opened and serial off
if (bCommInit == TRUE && (Chipset.IORam[IOC] & SON) == 0)
if (CommIsOpen() == TRUE && (Chipset.IORam[IOC] & SON) == 0)
{
CommClose(); // close COM port
bCommInit = FALSE;
}
return;
}
@ -551,7 +549,6 @@ loop:
{
OnToolMacroStop(); // close open keyboard macro handler
CommClose(); // close COM port
bCommInit = FALSE; // COM port not open
nState = SM_INVALID; // in invalid state
WaitForSingleObject(hEventShutdn,INFINITE);
if (nNextState == SM_RETURN) // go into return state

101
source/EXTERNAL.C Normal file
View file

@ -0,0 +1,101 @@
/*
* external.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#include "pch.h"
#include "Emu48.h"
#include "ops.h"
#define SAMPLES_PER_SEC 44100 // sound sampling rate
//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name
//#F0E4F #80F0F #80F0F #706D2 #80850 #80F0F =SFLAG53_56
// memory address for flags -53 to -56
// CdB for HP: add apples beep management
#define SFLAG53_56 ( (cCurrentRomType=='6') \
? 0xE0E4F \
: ( (cCurrentRomType=='A') \
? 0xF0E4F \
: ( (cCurrentRomType!='E' && cCurrentRomType!='X' && cCurrentRomType!='P' && cCurrentRomType!='2' && cCurrentRomType!='Q') \
? ( (cCurrentRomType=='S') \
? 0x706D2 \
: 0x80850 \
) \
: 0x80F0F \
) \
) \
)
VOID External(CHIPSET* w) // Beep patch
{
BYTE fbeep;
DWORD freq,dur;
freq = Npack(w->D,5); // frequency in Hz
dur = Npack(w->C,5); // duration in ms
Nread(&fbeep,SFLAG53_56,1); // fetch system flags -53 to -56
w->carry = TRUE; // setting of no beep
if (!(fbeep & 0x8) && freq) // bit -56 clear and frequency > 0 Hz
{
if (freq > 4400) freq = 4400; // high limit of HP (SX)
SoundBeep(freq,dur); // beeping
// estimate cpu cycles for beeping time (2MHz / 4MHz)
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
// original routine return with...
w->P = 0; // P=0
w->intk = TRUE; // INTON
w->carry = FALSE; // RTNCC
}
w->pc = rstkpop();
return;
}
VOID RCKBp(CHIPSET* w) // ROM Check Beep patch
{
DWORD dw2F,dwCpuFreq;
DWORD freq,dur;
BYTE f,d;
f = w->C[1]; // f = freq ctl
d = w->C[0]; // d = duration ctl
if (cCurrentRomType == 'S') // Clarke chip with 48S ROM
{
// CPU strobe frequency @ RATE 14 = 1.97MHz
dwCpuFreq = ((14 + 1) * 524288) >> 2;
dw2F = f * 126 + 262; // F=f*63+131
}
else // York chip with 48G and later ROM
{
// CPU strobe frequency @ RATE 27 = 3.67MHz
// CPU strobe frequency @ RATE 29 = 3.93MHz
dwCpuFreq = ((27 + 1) * 524288) >> 2;
dw2F = f * 180 + 367; // F=f*90+183.5
}
freq = dwCpuFreq / dw2F;
dur = (dw2F * (256 - 16 * d)) * 1000 / 2 / dwCpuFreq;
if (freq > 4400) freq = 4400; // high limit of HP
SoundBeep(freq,dur); // beeping
// estimate cpu cycles for beeping time (2MHz / 4MHz)
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
w->P = 0; // P=0
w->carry = FALSE; // RTNCC
w->pc = rstkpop();
return;
}

View file

@ -1730,7 +1730,7 @@ typedef struct _BmpFile
LPBYTE pbyFile; // buffer
} BMPFILE, FAR *LPBMPFILE, *PBMPFILE;
static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi)
static __inline WORD DibNumColors(__unaligned BITMAPINFOHEADER CONST *lpbi)
{
if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed;
@ -1738,7 +1738,7 @@ static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi)
return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0;
}
static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
static HPALETTE CreateBIPalette(__unaligned BITMAPINFOHEADER CONST *lpbi)
{
LOGPALETTE* pPal;
HPALETTE hpal = NULL;
@ -1747,12 +1747,9 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
BYTE green;
BYTE blue;
UINT i;
RGBQUAD* pRgb;
__unaligned RGBQUAD* pRgb;
if (!lpbi)
return NULL;
if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
if (!lpbi || lpbi->biSize != sizeof(BITMAPINFOHEADER))
return NULL;
// Get a pointer to the color table and the number of colors in it
@ -1816,22 +1813,19 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
{
LPBITMAPFILEHEADER pBmfh;
LPBITMAPINFO pBmi;
HBITMAP hBitmap;
DWORD dwFileSize;
DWORD dwFileSize;
hBitmap = NULL;
HBITMAP hBitmap = NULL;
// size of bitmap header information
// map memory to BITMAPFILEHEADER and BITMAPINFO
const LPBITMAPFILEHEADER pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile;
const __unaligned LPBITMAPINFO pBmi = (__unaligned LPBITMAPINFO) & pBmfh[1];
// size of bitmap header information & check for bitmap
dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if (pBmp->dwFileSize < dwFileSize) return NULL;
// check for bitmap
pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile;
if (pBmfh->bfType != 0x4D42) return NULL; // "BM"
pBmi = (LPBITMAPINFO) (pBmp->pbyFile + sizeof(BITMAPFILEHEADER));
if ( pBmp->dwFileSize < dwFileSize // minimum size to read data from BITMAPFILEHEADER + BITMAPINFOHEADER
|| pBmfh->bfType != 0x4D42) // "BM"
return NULL;
// size with color table
if (pBmi->bmiHeader.biCompression == BI_BITFIELDS)
@ -1852,7 +1846,7 @@ static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
else
{
dwFileSize += WIDTHBYTES(pBmi->bmiHeader.biWidth * pBmi->bmiHeader.biBitCount)
* labs(pBmi->bmiHeader.biHeight);
* labs(pBmi->bmiHeader.biHeight);
}
if (pBmp->dwFileSize < dwFileSize) return NULL;
@ -2452,11 +2446,15 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
if (hBitmap == NULL) goto quit;
pbySrc = pbyImage; // init source loop pointer
pbyPixels += bmi.bmiHeader.biSizeImage; // end of destination bitmap
// fill bottom up DIB pixel buffer with color information
for (nHeight = bmi.bmiHeader.biHeight - 1; nHeight >= 0; --nHeight)
for (nHeight = 0; nHeight < bmi.bmiHeader.biHeight; ++nHeight)
{
LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine;
LPBYTE pbyLine;
pbyPixels -= lBytesPerLine; // begin of previous row
pbyLine = pbyPixels; // row working copy
for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth)
{
@ -2465,8 +2463,6 @@ static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
*pbyLine++ = pbySrc[0]; // red
pbySrc += 3;
}
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
}
if (bPalette && hPalette == NULL)
@ -2482,12 +2478,6 @@ quit:
{
free(pbyImage); // free PNG image data
}
if (hBitmap != NULL && uError != 0) // creation failed
{
DeleteObject(hBitmap); // delete bitmap
hBitmap = NULL;
}
return hBitmap;
}

View file

@ -1,7 +1,7 @@
/*
LodePNG version 20210627
LodePNG version 20220717
Copyright (c) 2005-2021 Lode Vandevenne
Copyright (c) 2005-2022 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -44,10 +44,10 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for
#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
#endif /*_MSC_VER */
const char* LODEPNG_VERSION_STRING = "20210627";
const char* LODEPNG_VERSION_STRING = "20220717";
/*
This source file is built up in the following large parts. The code sections
This source file is divided into the following large parts. The code sections
with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
-Tools for C and common code for PNG and Zlib
-C Code for Zlib (huffman, deflate, ...)
@ -267,7 +267,7 @@ typedef struct ucvector {
} ucvector;
/*returns 1 if success, 0 if failure ==> nothing done*/
static unsigned ucvector_resize(ucvector* p, size_t size) {
static unsigned ucvector_reserve(ucvector* p, size_t size) {
if(size > p->allocsize) {
size_t newsize = size + (p->allocsize >> 1u);
void* data = lodepng_realloc(p->data, newsize);
@ -277,10 +277,15 @@ static unsigned ucvector_resize(ucvector* p, size_t size) {
}
else return 0; /*error: not enough memory*/
}
p->size = size;
return 1; /*success*/
}
/*returns 1 if success, 0 if failure ==> nothing done*/
static unsigned ucvector_resize(ucvector* p, size_t size) {
p->size = size;
return ucvector_reserve(p, size);
}
static ucvector ucvector_init(unsigned char* buffer, size_t size) {
ucvector v;
v.data = buffer;
@ -480,71 +485,62 @@ static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned c
ensureBits functions:
Ensures the reader can at least read nbits bits in one or more readBits calls,
safely even if not enough bits are available.
Returns 1 if there are enough bits available, 0 if not.
The nbits parameter is unused but is given for documentation purposes, error
checking for amount of bits must be done beforehand.
*/
/*See ensureBits documentation above. This one ensures exactly 1 bit */
/*static unsigned ensureBits1(LodePNGBitReader* reader) {
if(reader->bp >= reader->bitsize) return 0;
reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u);
return 1;
}*/
/*See ensureBits documentation above. This one ensures up to 9 bits */
static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE void ensureBits9(LodePNGBitReader* reader, size_t nbits) {
size_t start = reader->bp >> 3u;
size_t size = reader->size;
if(start + 1u < size) {
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u);
reader->buffer >>= (reader->bp & 7u);
return 1;
} else {
reader->buffer = 0;
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
if(start + 0u < size) reader->buffer = reader->data[start + 0];
reader->buffer >>= (reader->bp & 7u);
return reader->bp + nbits <= reader->bitsize;
}
(void)nbits;
}
/*See ensureBits documentation above. This one ensures up to 17 bits */
static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE void ensureBits17(LodePNGBitReader* reader, size_t nbits) {
size_t start = reader->bp >> 3u;
size_t size = reader->size;
if(start + 2u < size) {
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
((unsigned)reader->data[start + 2] << 16u);
reader->buffer >>= (reader->bp & 7u);
return 1;
} else {
reader->buffer = 0;
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
reader->buffer >>= (reader->bp & 7u);
return reader->bp + nbits <= reader->bitsize;
}
(void)nbits;
}
/*See ensureBits documentation above. This one ensures up to 25 bits */
static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE void ensureBits25(LodePNGBitReader* reader, size_t nbits) {
size_t start = reader->bp >> 3u;
size_t size = reader->size;
if(start + 3u < size) {
reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |
((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
reader->buffer >>= (reader->bp & 7u);
return 1;
} else {
reader->buffer = 0;
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
reader->buffer >>= (reader->bp & 7u);
return reader->bp + nbits <= reader->bitsize;
}
(void)nbits;
}
/*See ensureBits documentation above. This one ensures up to 32 bits */
static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE void ensureBits32(LodePNGBitReader* reader, size_t nbits) {
size_t start = reader->bp >> 3u;
size_t size = reader->size;
if(start + 4u < size) {
@ -552,7 +548,6 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi
((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
reader->buffer >>= (reader->bp & 7u);
reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u)));
return 1;
} else {
reader->buffer = 0;
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
@ -560,48 +555,28 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi
if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u);
reader->buffer >>= (reader->bp & 7u);
return reader->bp + nbits <= reader->bitsize;
}
(void)nbits;
}
/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */
static unsigned peekBits(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE unsigned peekBits(LodePNGBitReader* reader, size_t nbits) {
/* The shift allows nbits to be only up to 31. */
return reader->buffer & ((1u << nbits) - 1u);
}
/* Must have enough bits available with ensureBits */
static void advanceBits(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE void advanceBits(LodePNGBitReader* reader, size_t nbits) {
reader->buffer >>= nbits;
reader->bp += nbits;
}
/* Must have enough bits available with ensureBits */
static unsigned readBits(LodePNGBitReader* reader, size_t nbits) {
static LODEPNG_INLINE unsigned readBits(LodePNGBitReader* reader, size_t nbits) {
unsigned result = peekBits(reader, nbits);
advanceBits(reader, nbits);
return result;
}
/* Public for testing only. steps and result must have numsteps values. */
unsigned lode_png_test_bitreader(const unsigned char* data, size_t size,
size_t numsteps, const size_t* steps, unsigned* result) {
size_t i;
LodePNGBitReader reader;
unsigned error = LodePNGBitReader_init(&reader, data, size);
if(error) return 0;
for(i = 0; i < numsteps; i++) {
size_t step = steps[i];
unsigned ok;
if(step > 25) ok = ensureBits32(&reader, step);
else if(step > 17) ok = ensureBits25(&reader, step);
else if(step > 9) ok = ensureBits17(&reader, step);
else ok = ensureBits9(&reader, step);
if(!ok) return 0;
result[i] = readBits(&reader, step);
}
return 1;
}
#endif /*LODEPNG_COMPILE_DECODER*/
static unsigned reverseBits(unsigned bits, unsigned num) {
@ -736,10 +711,11 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
numpresent = 0;
for(i = 0; i < tree->numcodes; ++i) {
unsigned l = tree->lengths[i];
unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
/*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
unsigned reverse = reverseBits(symbol, l);
unsigned symbol, reverse;
if(l == 0) continue;
symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
/*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
reverse = reverseBits(symbol, l);
numpresent++;
if(l <= FIRSTBITS) {
@ -1103,11 +1079,10 @@ static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree*
advanceBits(reader, l);
return value;
} else {
unsigned index2;
advanceBits(reader, FIRSTBITS);
index2 = value + peekBits(reader, l - FIRSTBITS);
advanceBits(reader, codetree->table_len[index2] - FIRSTBITS);
return codetree->table_value[index2];
value += peekBits(reader, l - FIRSTBITS);
advanceBits(reader, codetree->table_len[value] - FIRSTBITS);
return codetree->table_value[value];
}
}
#endif /*LODEPNG_COMPILE_DECODER*/
@ -1140,7 +1115,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
unsigned* bitlen_cl = 0;
HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/
if(reader->bitsize - reader->bp < 14) return 49; /*error: the bit pointer is or will go past the memory*/
ensureBits17(reader, 14);
/*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
HLIT = readBits(reader, 5) + 257;
@ -1265,6 +1241,10 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
unsigned error = 0;
HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
HuffmanTree tree_d; /*the huffman tree for distance codes*/
const size_t reserved_size = 260; /* must be at least 258 for max length, and a few extra for adding a few extra literals */
int done = 0;
if(!ucvector_reserve(out, out->size + reserved_size)) return 83; /*alloc fail*/
HuffmanTree_init(&tree_ll);
HuffmanTree_init(&tree_d);
@ -1272,14 +1252,21 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);
else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);
while(!error) /*decode all symbols until end reached, breaks at end code*/ {
while(!error && !done) /*decode all symbols until end reached, breaks at end code*/ {
/*code_ll is literal, length or end code*/
unsigned code_ll;
ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */
/* ensure enough bits for 2 huffman code reads (15 bits each): if the first is a literal, a second literal is read at once. This
appears to be slightly faster, than ensuring 20 bits here for 1 huffman symbol and the potential 5 extra bits for the length symbol.*/
ensureBits32(reader, 30);
code_ll = huffmanDecodeSymbol(reader, &tree_ll);
if(code_ll <= 255) {
/*slightly faster code path if multiple literals in a row*/
out->data[out->size++] = (unsigned char)code_ll;
code_ll = huffmanDecodeSymbol(reader, &tree_ll);
}
if(code_ll <= 255) /*literal symbol*/ {
if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/);
out->data[out->size - 1] = (unsigned char)code_ll;
out->data[out->size++] = (unsigned char)code_ll;
} else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {
unsigned code_d, distance;
unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
@ -1292,6 +1279,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
if(numextrabits_l != 0) {
/* bits already ensured above */
ensureBits25(reader, 5);
length += readBits(reader, numextrabits_l);
}
@ -1319,7 +1307,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
backward = start - distance;
if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/);
out->size += length;
if(distance < length) {
size_t forward;
lodepng_memcpy(out->data + start, out->data + backward, distance);
@ -1331,10 +1319,13 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
lodepng_memcpy(out->data + start, out->data + backward, length);
}
} else if(code_ll == 256) {
break; /*end code, break the loop*/
done = 1; /*end code, finish the loop*/
} else /*if(code_ll == INVALIDSYMBOL)*/ {
ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
}
if(out->allocsize - out->size < reserved_size) {
if(!ucvector_reserve(out, out->size + reserved_size)) ERROR_BREAK(83); /*alloc fail*/
}
/*check if any of the ensureBits above went out of bounds*/
if(reader->bp > reader->bitsize) {
/*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
@ -1377,8 +1368,11 @@ static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader,
/*read the literal data: LEN bytes are now stored in the out buffer*/
if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/
lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
bytepos += LEN;
/*out->data can be NULL (when LEN is zero), and arithmetics on NULL ptr is undefined*/
if (LEN) {
lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
bytepos += LEN;
}
reader->bp = bytepos << 3u;
@ -1396,7 +1390,8 @@ static unsigned lodepng_inflatev(ucvector* out,
while(!BFINAL) {
unsigned BTYPE;
if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/
if(reader.bitsize - reader.bp < 3) return 52; /*error, bit pointer will jump past memory*/
ensureBits9(&reader, 3);
BFINAL = readBits(&reader, 1);
BTYPE = readBits(&reader, 2);
@ -2378,7 +2373,7 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0,
/* ////////////////////////////////////////////////////////////////////////// */
#ifndef LODEPNG_NO_COMPILE_CRC
#ifdef LODEPNG_COMPILE_CRC
/* CRC polynomial: 0xedb88320 */
static unsigned lodepng_crc32_table[256] = {
0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u,
@ -2424,9 +2419,11 @@ unsigned lodepng_crc32(const unsigned char* data, size_t length) {
}
return r ^ 0xffffffffu;
}
#else /* !LODEPNG_NO_COMPILE_CRC */
#else /* LODEPNG_COMPILE_CRC */
/*in this case, the function is only declared here, and must be defined externally
so that it will be linked in*/
unsigned lodepng_crc32(const unsigned char* data, size_t length);
#endif /* !LODEPNG_NO_COMPILE_CRC */
#endif /* LODEPNG_COMPILE_CRC */
/* ////////////////////////////////////////////////////////////////////////// */
/* / Reading and writing PNG color channel bits / */
@ -2464,7 +2461,7 @@ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream,
/* ////////////////////////////////////////////////////////////////////////// */
unsigned lodepng_chunk_length(const unsigned char* chunk) {
return lodepng_read32bitInt(&chunk[0]);
return lodepng_read32bitInt(chunk);
}
void lodepng_chunk_type(char type[5], const unsigned char* chunk) {
@ -2514,34 +2511,32 @@ void lodepng_chunk_generate_crc(unsigned char* chunk) {
}
unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) {
if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/
size_t available_size = (size_t)(end - chunk);
if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/
if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47
&& chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {
/* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
return chunk + 8;
} else {
size_t total_chunk_length;
unsigned char* result;
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
result = chunk + total_chunk_length;
if(result < chunk) return end; /*pointer overflow*/
return result;
if(total_chunk_length > available_size) return end; /*outside of range*/
return chunk + total_chunk_length;
}
}
const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) {
if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/
size_t available_size = (size_t)(end - chunk);
if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/
if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47
&& chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {
/* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
return chunk + 8;
} else {
size_t total_chunk_length;
const unsigned char* result;
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
result = chunk + total_chunk_length;
if(result < chunk) return end; /*pointer overflow*/
return result;
if(total_chunk_length > available_size) return end; /*outside of range*/
return chunk + total_chunk_length;
}
}
@ -2586,7 +2581,7 @@ the data is at chunk + 8. To finalize chunk, add the data, then use
lodepng_chunk_generate_crc */
static unsigned lodepng_chunk_init(unsigned char** chunk,
ucvector* out,
unsigned length, const char* type) {
size_t length, const char* type) {
size_t new_length = out->size;
if(lodepng_addofl(new_length, length, &new_length)) return 77;
if(lodepng_addofl(new_length, 12, &new_length)) return 77;
@ -2594,7 +2589,7 @@ static unsigned lodepng_chunk_init(unsigned char** chunk,
*chunk = out->data + new_length - length - 12u;
/*1: length*/
lodepng_set32bitInt(*chunk, length);
lodepng_set32bitInt(*chunk, (unsigned)length);
/*2: chunk name (4 letters)*/
lodepng_memcpy(*chunk + 4, type, 4);
@ -2604,7 +2599,7 @@ static unsigned lodepng_chunk_init(unsigned char** chunk,
/* like lodepng_chunk_create but with custom allocsize */
static unsigned lodepng_chunk_createv(ucvector* out,
unsigned length, const char* type, const unsigned char* data) {
size_t length, const char* type, const unsigned char* data) {
unsigned char* chunk;
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type));
@ -3051,6 +3046,9 @@ void lodepng_info_init(LodePNGInfo* info) {
info->iccp_name = NULL;
info->iccp_profile = NULL;
info->sbit_defined = 0;
info->sbit_r = info->sbit_g = info->sbit_b = info->sbit_a = 0;
LodePNGUnknownChunks_init(info);
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
}
@ -3945,7 +3943,7 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out,
if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize
&& mode_in->bitdepth == mode_out->bitdepth) {
/*If input should have same palette colors, keep original to preserve its order and prevent conversion*/
lodepng_color_mode_cleanup(mode_out);
lodepng_color_mode_cleanup(mode_out); /*clears palette, keeps the above set colortype and bitdepth fields as-is*/
lodepng_color_mode_copy(mode_out, mode_in);
}
} else /*8-bit or 16-bit per channel*/ {
@ -4135,10 +4133,9 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
too much code. Whether this speeds up anything depends on compiler and settings. */
if(bytewidth >= 4) {
for(; i + 3 < length; i += 4, j += 4) {
unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
unsigned char s3 = scanline[i + 3], r3 = recon[j + 3], p3 = precon[i + 3];
unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3];
unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3];
unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3];
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
@ -4146,17 +4143,18 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
}
} else if(bytewidth >= 3) {
for(; i + 2 < length; i += 3, j += 3) {
unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2];
unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2];
unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2];
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
}
} else if(bytewidth >= 2) {
for(; i + 1 < length; i += 2, j += 2) {
unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1];
unsigned char r0 = recon[j + 0], r1 = recon[j + 1];
unsigned char p0 = precon[i + 0], p1 = precon[i + 1];
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
}
@ -4732,6 +4730,47 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings*
if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/
return error;
}
/*significant bits chunk (sBIT)*/
static unsigned readChunk_sBIT(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {
unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth;
if(info->color.colortype == LCT_GREY) {
/*error: this chunk must be 1 bytes for grayscale image*/
if(chunkLength != 1) return 114;
if(data[0] == 0 || data[0] > bitdepth) return 115;
info->sbit_defined = 1;
info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/
} else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) {
/*error: this chunk must be 3 bytes for RGB and palette image*/
if(chunkLength != 3) return 114;
if(data[0] == 0 || data[1] == 0 || data[2] == 0) return 115;
if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth) return 115;
info->sbit_defined = 1;
info->sbit_r = data[0];
info->sbit_g = data[1];
info->sbit_b = data[2];
} else if(info->color.colortype == LCT_GREY_ALPHA) {
/*error: this chunk must be 2 byte for grayscale with alpha image*/
if(chunkLength != 2) return 114;
if(data[0] == 0 || data[1] == 0) return 115;
if(data[0] > bitdepth || data[1] > bitdepth) return 115;
info->sbit_defined = 1;
info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/
info->sbit_a = data[1];
} else if(info->color.colortype == LCT_RGBA) {
/*error: this chunk must be 4 bytes for grayscale image*/
if(chunkLength != 4) return 114;
if(data[0] == 0 || data[1] == 0 || data[2] == 0 || data[3] == 0) return 115;
if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth || data[3] > bitdepth) return 115;
info->sbit_defined = 1;
info->sbit_r = data[0];
info->sbit_g = data[1];
info->sbit_b = data[2];
info->sbit_a = data[3];
}
return 0; /* OK */
}
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
@ -4746,7 +4785,7 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
chunkLength = lodepng_chunk_length(chunk);
if(chunkLength > 2147483647) return 63;
data = lodepng_chunk_data_const(chunk);
if(data + chunkLength + 4 > in + insize) return 30;
if(chunkLength + 12 > insize - pos) return 30;
if(lodepng_chunk_type_equals(chunk, "PLTE")) {
error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
@ -4773,6 +4812,8 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
error = readChunk_sRGB(&state->info_png, data, chunkLength);
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
} else if(lodepng_chunk_type_equals(chunk, "sBIT")) {
error = readChunk_sBIT(&state->info_png, data, chunkLength);
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
} else {
/* unhandled chunk is ok (is not an error) */
@ -4791,7 +4832,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
LodePNGState* state,
const unsigned char* in, size_t insize) {
unsigned char IEND = 0;
const unsigned char* chunk;
const unsigned char* chunk; /*points to beginning of next chunk*/
unsigned char* idat; /*the data from idat chunks, zlib compressed*/
size_t idatsize = 0;
unsigned char* scanlines = 0;
@ -4827,14 +4868,15 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
while(!IEND && !state->error) {
unsigned chunkLength;
const unsigned char* data; /*the data in the chunk*/
size_t pos = (size_t)(chunk - in);
/*error: size of the in buffer too small to contain next chunk*/
if((size_t)((chunk - in) + 12) > insize || chunk < in) {
/*error: next chunk out of bounds of the in buffer*/
if(chunk < in || pos + 12 > insize) {
if(state->decoder.ignore_end) break; /*other errors may still happen though*/
CERROR_BREAK(state->error, 30);
}
/*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
/*length of the data of the chunk, excluding the 12 bytes for length, chunk type and CRC*/
chunkLength = lodepng_chunk_length(chunk);
/*error: chunk length larger than the max PNG chunk size*/
if(chunkLength > 2147483647) {
@ -4842,8 +4884,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
CERROR_BREAK(state->error, 63);
}
if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) {
CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/
if(pos + (size_t)chunkLength + 12 > insize || pos + (size_t)chunkLength + 12 < pos) {
CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk (or int overflow)*/
}
data = lodepng_chunk_data_const(chunk);
@ -4917,6 +4959,9 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
if(state->error) break;
} else if(lodepng_chunk_type_equals(chunk, "sBIT")) {
state->error = readChunk_sBIT(&state->info_png, data, chunkLength);
if(state->error) break;
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
} else /*it's not an implemented chunk type, so ignore it: skip over the data*/ {
/*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
@ -5152,7 +5197,11 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) {
unsigned char* chunk;
size_t i, j = 8;
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)info->palettesize * 3, "PLTE"));
if(info->palettesize == 0 || info->palettesize > 256) {
return 68; /*invalid palette size, it is only allowed to be 1-256*/
}
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE"));
for(i = 0; i != info->palettesize; ++i) {
/*add all channels except alpha channel*/
@ -5176,7 +5225,7 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) {
--amount;
}
if(amount) {
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)amount, "tRNS"));
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS"));
/*add the alpha channel values from the palette*/
for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3];
}
@ -5210,7 +5259,7 @@ static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t d
error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings);
if(!error) {
error = lodepng_chunk_createv(out, (unsigned)zlibsize, "IDAT", zlib);
error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib);
}
lodepng_free(zlib);
return error;
@ -5227,7 +5276,7 @@ static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* te
size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring);
size_t size = keysize + 1 + textsize;
if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, (unsigned)size, "tEXt"));
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt"));
lodepng_memcpy(chunk + 8, keyword, keysize);
chunk[8 + keysize] = 0; /*null termination char*/
lodepng_memcpy(chunk + 9 + keysize, textstring, textsize);
@ -5249,7 +5298,7 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te
(const unsigned char*)textstring, textsize, zlibsettings);
if(!error) {
size_t size = keysize + 2 + compressedsize;
error = lodepng_chunk_init(&chunk, out, (unsigned)size, "zTXt");
error = lodepng_chunk_init(&chunk, out, size, "zTXt");
}
if(!error) {
lodepng_memcpy(chunk + 8, keyword, keysize);
@ -5280,7 +5329,7 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyw
}
if(!error) {
size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize);
error = lodepng_chunk_init(&chunk, out, (unsigned)size, "iTXt");
error = lodepng_chunk_init(&chunk, out, size, "iTXt");
}
if(!error) {
size_t pos = 8;
@ -5393,7 +5442,7 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom
info->iccp_profile, info->iccp_profile_size, zlibsettings);
if(!error) {
size_t size = keysize + 2 + compressedsize;
error = lodepng_chunk_init(&chunk, out, (unsigned)size, "iCCP");
error = lodepng_chunk_init(&chunk, out, size, "iCCP");
}
if(!error) {
lodepng_memcpy(chunk + 8, info->iccp_name, keysize);
@ -5407,6 +5456,42 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom
return error;
}
static unsigned addChunk_sBIT(ucvector* out, const LodePNGInfo* info) {
unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth;
unsigned char* chunk = 0;
if(info->color.colortype == LCT_GREY) {
if(info->sbit_r == 0 || info->sbit_r > bitdepth) return 115;
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "sBIT"));
chunk[8] = info->sbit_r;
} else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) {
if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0) return 115;
if(info->sbit_r > bitdepth || info->sbit_g > bitdepth || info->sbit_b > bitdepth) return 115;
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 3, "sBIT"));
chunk[8] = info->sbit_r;
chunk[9] = info->sbit_g;
chunk[10] = info->sbit_b;
} else if(info->color.colortype == LCT_GREY_ALPHA) {
if(info->sbit_r == 0 || info->sbit_a == 0) return 115;
if(info->sbit_r > bitdepth || info->sbit_a > bitdepth) return 115;
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "sBIT"));
chunk[8] = info->sbit_r;
chunk[9] = info->sbit_a;
} else if(info->color.colortype == LCT_RGBA) {
if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0 || info->sbit_a == 0 ||
info->sbit_r > bitdepth || info->sbit_g > bitdepth ||
info->sbit_b > bitdepth || info->sbit_a > bitdepth) {
return 115;
}
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "sBIT"));
chunk[8] = info->sbit_r;
chunk[9] = info->sbit_g;
chunk[10] = info->sbit_b;
chunk[11] = info->sbit_a;
}
if(chunk) lodepng_chunk_generate_crc(chunk);
return 0;
}
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
@ -5852,8 +5937,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
ucvector outv = ucvector_init(NULL, 0);
LodePNGInfo info;
const LodePNGInfo* info_png = &state->info_png;
LodePNGColorMode auto_color;
lodepng_info_init(&info);
lodepng_color_mode_init(&auto_color);
/*provide some proper output values if error will happen*/
*out = 0;
@ -5863,6 +5950,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
/*check input values validity*/
if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette)
&& (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) {
/*this error is returned even if auto_convert is enabled and thus encoder could
generate the palette by itself: while allowing this could be possible in theory,
it may complicate the code or edge cases, and always requiring to give a palette
when setting this color type is a simpler contract*/
state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
goto cleanup;
}
@ -5883,6 +5974,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
lodepng_info_copy(&info, &state->info_png);
if(state->encoder.auto_convert) {
LodePNGColorStats stats;
unsigned allow_convert = 1;
lodepng_color_stats_init(&stats);
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
if(info_png->iccp_defined &&
@ -5904,23 +5996,85 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
/*the background chunk's color must be taken into account as well*/
unsigned r = 0, g = 0, b = 0;
LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16);
lodepng_convert_rgb(&r, &g, &b, info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color);
lodepng_convert_rgb(&r, &g, &b,
info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color);
state->error = lodepng_color_stats_add(&stats, r, g, b, 65535);
if(state->error) goto cleanup;
}
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
state->error = auto_choose_color(&info.color, &state->info_raw, &stats);
state->error = auto_choose_color(&auto_color, &state->info_raw, &stats);
if(state->error) goto cleanup;
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
/*also convert the background chunk*/
if(info_png->background_defined) {
if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b,
info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) {
state->error = 104;
goto cleanup;
if(info_png->sbit_defined) {
/*if sbit is defined, due to strict requirements of which sbit values can be present for which color modes,
auto_convert can't be done in many cases. However, do support a few cases here.
TODO: more conversions may be possible, and it may also be possible to get a more appropriate color type out of
auto_choose_color if knowledge about sbit is used beforehand
*/
unsigned sbit_max = LODEPNG_MAX(LODEPNG_MAX(LODEPNG_MAX(info_png->sbit_r, info_png->sbit_g),
info_png->sbit_b), info_png->sbit_a);
unsigned equal = (!info_png->sbit_g || info_png->sbit_g == info_png->sbit_r)
&& (!info_png->sbit_b || info_png->sbit_b == info_png->sbit_r)
&& (!info_png->sbit_a || info_png->sbit_a == info_png->sbit_r);
allow_convert = 0;
if(info.color.colortype == LCT_PALETTE &&
auto_color.colortype == LCT_PALETTE) {
/* input and output are palette, and in this case it may happen that palette data is
expected to be copied from info_raw into the info_png */
allow_convert = 1;
}
/*going from 8-bit RGB to palette (or 16-bit as long as sbit_max <= 8) is possible
since both are 8-bit RGB for sBIT's purposes*/
if(info.color.colortype == LCT_RGB &&
auto_color.colortype == LCT_PALETTE && sbit_max <= 8) {
allow_convert = 1;
}
/*going from 8-bit RGBA to palette is also ok but only if sbit_a is exactly 8*/
if(info.color.colortype == LCT_RGBA && auto_color.colortype == LCT_PALETTE &&
info_png->sbit_a == 8 && sbit_max <= 8) {
allow_convert = 1;
}
/*going from 16-bit RGB(A) to 8-bit RGB(A) is ok if all sbit values are <= 8*/
if((info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA) && info.color.bitdepth == 16 &&
auto_color.colortype == info.color.colortype && auto_color.bitdepth == 8 &&
sbit_max <= 8) {
allow_convert = 1;
}
/*going to less channels is ok if all bit values are equal (all possible values in sbit,
as well as the chosen bitdepth of the result). Due to how auto_convert works,
we already know that auto_color.colortype has less than or equal amount of channels than
info.colortype. Palette is not used here. This conversion is not allowed if
info_png->sbit_r < auto_color.bitdepth, because specifically for alpha, non-presence of
an sbit value heavily implies that alpha's bit depth is equal to the PNG bit depth (rather
than the bit depths set in the r, g and b sbit values, by how the PNG specification describes
handling tRNS chunk case with sBIT), so be conservative here about ignoring user input.*/
if(info.color.colortype != LCT_PALETTE && auto_color.colortype != LCT_PALETTE &&
equal && info_png->sbit_r == auto_color.bitdepth) {
allow_convert = 1;
}
}
#endif
if(state->encoder.force_palette) {
if(info.color.colortype != LCT_GREY && info.color.colortype != LCT_GREY_ALPHA &&
(auto_color.colortype == LCT_GREY || auto_color.colortype == LCT_GREY_ALPHA)) {
/*user speficially forced a PLTE palette, so cannot convert to grayscale types because
the PNG specification only allows writing a suggested palette in PLTE for truecolor types*/
allow_convert = 0;
}
}
if(allow_convert) {
lodepng_color_mode_copy(&info.color, &auto_color);
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
/*also convert the background chunk*/
if(info_png->background_defined) {
if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b,
info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) {
state->error = 104;
goto cleanup;
}
}
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
}
}
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
if(info_png->iccp_defined) {
@ -5991,6 +6145,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
state->error = addChunk_cHRM(&outv, &info);
if(state->error) goto cleanup;
}
if(info_png->sbit_defined) {
state->error = addChunk_sBIT(&outv, &info);
if(state->error) goto cleanup;
}
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
/*PLTE*/
if(info.color.colortype == LCT_PALETTE) {
@ -6097,6 +6255,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
cleanup:
lodepng_info_cleanup(&info);
lodepng_free(data);
lodepng_color_mode_cleanup(&auto_color);
/*instead of cleaning the vector up, give it to the output*/
*out = outv.data;
@ -6291,6 +6450,8 @@ const char* lodepng_error_text(unsigned code) {
/*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents
unreasonable memory consumption when decoding due to impossibly large ICC profile*/
case 113: return "ICC profile unreasonably large";
case 114: return "sBIT chunk has wrong size for the color type of the image";
case 115: return "sBIT value out of range";
}
return "unknown error code";
}
@ -6327,7 +6488,7 @@ unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, si
size_t buffersize = 0;
unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);
if(buffer) {
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
@ -6346,7 +6507,7 @@ unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size
size_t buffersize = 0;
unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
if(buffer) {
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
@ -6391,7 +6552,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const
state.info_raw.colortype = colortype;
state.info_raw.bitdepth = bitdepth;
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
out.insert(out.end(), buffer, &buffer[buffersize]);
}
lodepng_free(buffer);
return error;
@ -6409,7 +6570,7 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
if(buffer && !error) {
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
out.insert(out.end(), buffer, &buffer[buffersize]);
}
lodepng_free(buffer);
return error;
@ -6441,7 +6602,7 @@ unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsign
size_t buffersize;
unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
if(buffer) {
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
@ -6461,7 +6622,7 @@ unsigned encode(std::vector<unsigned char>& out,
size_t buffersize;
unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
if(buffer) {
out.insert(out.end(), &buffer[0], &buffer[buffersize]);
out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;

View file

@ -1,7 +1,7 @@
/*
LodePNG version 20210627
LodePNG version 20220717
Copyright (c) 2005-2021 Lode Vandevenne
Copyright (c) 2005-2022 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -35,43 +35,50 @@ The following #defines are used to create code sections. They can be disabled
to disable code sections, which can give faster compile time and smaller binary.
The "NO_COMPILE" defines are designed to be used to pass as defines to the
compiler command to disable them without modifying this header, e.g.
-DLODEPNG_NO_COMPILE_ZLIB for gcc.
In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to
allow implementing a custom lodepng_crc32.
-DLODEPNG_NO_COMPILE_ZLIB for gcc or clang.
*/
/*deflate & zlib. If disabled, you must specify alternative zlib functions in
the custom_zlib field of the compress and decompress settings*/
#ifndef LODEPNG_NO_COMPILE_ZLIB
/*pass -DLODEPNG_NO_COMPILE_ZLIB to the compiler to disable this, or comment out LODEPNG_COMPILE_ZLIB below*/
#define LODEPNG_COMPILE_ZLIB
#endif
/*png encoder and png decoder*/
#ifndef LODEPNG_NO_COMPILE_PNG
/*pass -DLODEPNG_NO_COMPILE_PNG to the compiler to disable this, or comment out LODEPNG_COMPILE_PNG below*/
#define LODEPNG_COMPILE_PNG
#endif
/*deflate&zlib decoder and png decoder*/
#ifndef LODEPNG_NO_COMPILE_DECODER
/*pass -DLODEPNG_NO_COMPILE_DECODER to the compiler to disable this, or comment out LODEPNG_COMPILE_DECODER below*/
#define LODEPNG_COMPILE_DECODER
#endif
/*deflate&zlib encoder and png encoder*/
#ifndef LODEPNG_NO_COMPILE_ENCODER
/*pass -DLODEPNG_NO_COMPILE_ENCODER to the compiler to disable this, or comment out LODEPNG_COMPILE_ENCODER below*/
#define LODEPNG_COMPILE_ENCODER
#endif
/*the optional built in harddisk file loading and saving functions*/
#ifndef LODEPNG_NO_COMPILE_DISK
/*pass -DLODEPNG_NO_COMPILE_DISK to the compiler to disable this, or comment out LODEPNG_COMPILE_DISK below*/
#define LODEPNG_COMPILE_DISK
#endif
/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
/*pass -DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS to the compiler to disable this,
or comment out LODEPNG_COMPILE_ANCILLARY_CHUNKS below*/
#define LODEPNG_COMPILE_ANCILLARY_CHUNKS
#endif
/*ability to convert error numerical codes to English text string*/
#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
/*pass -DLODEPNG_NO_COMPILE_ERROR_TEXT to the compiler to disable this,
or comment out LODEPNG_COMPILE_ERROR_TEXT below*/
#define LODEPNG_COMPILE_ERROR_TEXT
#endif
@ -79,12 +86,24 @@ the custom_zlib field of the compress and decompress settings*/
you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
source files with custom allocators.*/
#ifndef LODEPNG_NO_COMPILE_ALLOCATORS
/*pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler to disable the built-in ones,
or comment out LODEPNG_COMPILE_ALLOCATORS below*/
#define LODEPNG_COMPILE_ALLOCATORS
#endif
/*Disable built-in CRC function, in that case a custom implementation of
lodepng_crc32 must be defined externally so that it can be linked in.*/
#ifndef LODEPNG_NO_COMPILE_CRC
/*pass -DLODEPNG_NO_COMPILE_CRC to the compiler to disable the built-in one,
or comment out LODEPNG_COMPILE_CRC below*/
#define LODEPNG_COMPILE_CRC
#endif
/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
#ifdef __cplusplus
#ifndef LODEPNG_NO_COMPILE_CPP
/*pass -DLODEPNG_NO_COMPILE_CPP to the compiler to disable C++ (not needed if a C-only compiler),
or comment out LODEPNG_COMPILE_CPP below*/
#define LODEPNG_COMPILE_CPP
#endif
#endif
@ -374,8 +393,10 @@ typedef struct LodePNGColorMode {
The alpha channels must be set as well, set them to 255 for opaque images.
When decoding, by default you can ignore this palette, since LodePNG already
fills the palette colors in the pixels of the raw RGBA output.
When decoding, with the default settings you can ignore this palette, since
LodePNG already fills the palette colors in the pixels of the raw RGBA output,
but when decoding to the original PNG color mode it is needed to reconstruct
the colors.
The palette is only supported for color type 3.
*/
@ -465,10 +486,12 @@ typedef struct LodePNGInfo {
with values truncated to the bit depth in the unsigned integer.
For grayscale and palette PNGs, the value is stored in background_r. The values
in background_g and background_b are then unused.
in background_g and background_b are then unused. The decoder will set them
equal to background_r, the encoder ignores them in this case.
So when decoding, you may get these in a different color mode than the one you requested
for the raw pixels.
When decoding, you may get these in a different color mode than the one you requested
for the raw pixels: the colortype and bitdepth defined by info_png.color, that is the
ones defined in the header of the PNG image, are used.
When encoding with auto_convert, you must use the color model defined in info_png.color for
these values. The encoder normally ignores info_png.color when auto_convert is on, but will
@ -535,7 +558,7 @@ typedef struct LodePNGInfo {
unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/
/*
Color profile related chunks: gAMA, cHRM, sRGB, iCPP
Color profile related chunks: gAMA, cHRM, sRGB, iCPP, sBIT
LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color
profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please
@ -598,6 +621,45 @@ typedef struct LodePNGInfo {
unsigned char* iccp_profile;
unsigned iccp_profile_size; /* The size of iccp_profile in bytes */
/*
sBIT chunk: significant bits. Optional metadata, only set this if needed.
If defined, these values give the bit depth of the original data. Since PNG only stores 1, 2, 4, 8 or 16-bit
per channel data, the significant bits value can be used to indicate the original encoded data has another
sample depth, such as 10 or 12.
Encoders using this value, when storing the pixel data, should use the most significant bits
of the data to store the original bits, and use a good sample depth scaling method such as
"left bit replication" to fill in the least significant bits, rather than fill zeroes.
Decoders using this value, if able to work with data that's e.g. 10-bit or 12-bit, should right
shift the data to go back to the original bit depth, but decoders are also allowed to ignore
sbit and work e.g. with the 8-bit or 16-bit data from the PNG directly, since thanks
to the encoder contract, the values encoded in PNG are in valid range for the PNG bit depth.
For grayscale images, sbit_g and sbit_b are not used, and for images that don't use color
type RGBA or grayscale+alpha, sbit_a is not used (it's not used even for palette images with
translucent palette values, or images with color key). The values that are used must be
greater than zero and smaller than or equal to the PNG bit depth.
The color type from the header in the PNG image defines these used and unused fields: if
decoding with a color mode conversion, such as always decoding to RGBA, this metadata still
only uses the color type of the original PNG, and may e.g. lack the alpha channel info
if the PNG was RGB. When encoding with auto_convert (as well as without), also always the
color model defined in info_png.color determines this.
NOTE: enabling sbit can hurt compression, because the encoder can then not always use
auto_convert to choose a more optimal color mode for the data, because the PNG format has
strict requirements for the allowed sbit values in combination with color modes.
For example, setting these fields to 10-bit will force the encoder to keep using a 16-bit per channel
color mode, even if the pixel data would in fact fit in a more efficient 8-bit mode.
*/
unsigned sbit_defined; /*is significant bits given? if not, the values below are unused*/
unsigned sbit_r; /*red or gray component of significant bits*/
unsigned sbit_g; /*green component of significant bits*/
unsigned sbit_b; /*blue component of significant bits*/
unsigned sbit_a; /*alpha component of significant bits*/
/* End of color profile related chunks */
@ -770,7 +832,11 @@ typedef struct LodePNGEncoderSettings {
const unsigned char* predefined_filters;
/*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).
If colortype is 3, PLTE is _always_ created.*/
If colortype is 3, PLTE is always created. If color type is explicitely set
to a grayscale type (1 or 4), this is not done and is ignored. If enabling this,
a palette must be present in the info_png.
NOTE: enabling this may worsen compression if auto_convert is used to choose
optimal color mode, because it cannot use grayscale color modes in this case*/
unsigned force_palette;
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
/*add LodePNG identifier and version as a text chunk, for debugging*/
@ -824,8 +890,8 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h,
#endif /*LODEPNG_COMPILE_DECODER*/
/*
Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it
read in the state. Returns error code on failure.
Reads one metadata chunk (other than IHDR, which is handled by lodepng_inspect)
of the PNG file and outputs what it read in the state. Returns error code on failure.
Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const
to find the desired chunk type, and if non null use lodepng_inspect_chunk (with
chunk_pointer - start_of_file as pos).
@ -1103,7 +1169,7 @@ TODO:
[.] check compatibility with various compilers - done but needs to be redone for every newer version
[X] converting color to 16-bit per channel types
[X] support color profile chunk types (but never let them touch RGB values by default)
[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST)
[ ] support all public PNG chunk types (almost done except sPLT and hIST)
[ ] make sure encoder generates no chunks with size > (2^31)-1
[ ] partial decoding (stream processing)
[X] let the "isFullyOpaque" function check color keys and transparent palettes too
@ -1230,18 +1296,16 @@ The following features are supported by the decoder:
gAMA: RGB gamma correction
iCCP: ICC color profile
sRGB: rendering intent
sBIT: significant bits
1.2. features not supported
---------------------------
The following features are _not_ supported:
The following features are not (yet) supported:
*) some features needed to make a conformant PNG-Editor might be still missing.
*) partial loading/stream processing. All data must be available and is processed in one call.
*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG:
sBIT
hIST
sPLT
*) The hIST and sPLT public chunks are not (yet) supported but treated as unknown chunks
2. C and C++ version
@ -1845,6 +1909,8 @@ symbol.
Not all changes are listed here, the commit history in github lists more:
https://github.com/lvandeve/lodepng
*) 13 jun 2022: added support for the sBIT chunk.
*) 09 jan 2022: minor decoder speed improvements.
*) 27 jun 2021: added warnings that file reading/writing functions don't support
wide-character filenames (support for this is not planned, opening files is
not the core part of PNG decoding/decoding and is platform dependent).
@ -2015,5 +2081,5 @@ Domain: gmail dot com.
Account: lode dot vandevenne.
Copyright (c) 2005-2021 Lode Vandevenne
Copyright (c) 2005-2022 Lode Vandevenne
*/

View file

@ -1161,8 +1161,11 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate)
case 0x15: // RBR MSB
if (bUpdate)
{
Chipset.IORam[RCS] &= ~RBF;
*a = Chipset.IORam[d]; // return RBR value
if (d==0x15) // reading RBR MSB
{
Chipset.IORam[RCS] &= ~RBF; // clear Receive Buffer Full flag
}
UpdateUSRQ(); // update USRQ
rbr_acc = TRUE; // search for new RBR value
#if defined DEBUG_SERIAL
@ -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 Input, Enable IR UART mode, Enable IR Interrupt, IR Event
case 0x1A:
// COM port open and EIRU bit changed
if (bCommInit && ((c^Chipset.IORam[d]) & EIRU) != 0)
// EIRU bit changed
if (((c^Chipset.IORam[d]) & EIRU) != 0)
{
// save new value for COM open
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
// reopen COM port with new setting
bCommInit = CommOpen(szSerialWire,szSerialIr);
CommOpen(szSerialWire,szSerialIr);
}
Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7);
#if defined DEBUG_SERIAL

View file

@ -84,7 +84,7 @@ VOID MruCleanup(VOID)
{
for (i = 0; i < nEntry; ++i) // cleanup each entry
{
if (ppszFiles[i] != NULL)
if (ppszFiles[i] != NULL) // valid entry
free(ppszFiles[i]); // cleanup entry
}
@ -111,7 +111,7 @@ VOID MruAdd(LPCTSTR lpszEntry)
for (i = 0; i < nEntry; ++i)
{
// already in table -> quit
if ( ppszFiles[i] != NULL
if ( ppszFiles[i] != NULL // valid entry
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
{
MruMoveTop(i); // move to top and update menu
@ -120,7 +120,7 @@ VOID MruAdd(LPCTSTR lpszEntry)
}
i = nEntry - 1; // last index
if (ppszFiles[i] != NULL)
if (ppszFiles[i] != NULL) // valid entry
free(ppszFiles[i]); // free oldest entry
for (; i > 0; --i) // move old entries 1 line down
@ -173,16 +173,43 @@ UINT MruEntries(VOID)
return nEntry;
}
LPCTSTR MruFilename(UINT nIndex)
UINT MruID(LPCTSTR lpszEntry)
{
LPCTSTR lpszName = _T("");
TCHAR szFilename[MAX_PATH];
LPTSTR lpFilePart;
UINT i;
if (ppszFiles != NULL) // MRU initialized
{
_ASSERT(nEntry > 0); // must have entries
// get full path name
GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart);
// look if entry is already in table
for (i = 0; i < nEntry; ++i)
{
if ( ppszFiles[i] != NULL // valid entry
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
{
return i; // return ID
}
}
}
return (UINT) -1; // not found
}
VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize)
{
*szFilename = 0; // not found
// MRU initialized and index inside valid range
if (ppszFiles != NULL && nIndex < nEntry)
{
lpszName = ppszFiles[nIndex];
_ASSERT(ppszFiles[nIndex] != NULL); // valid entry
lstrcpyn(szFilename,ppszFiles[nIndex],nBuffersize);
}
return lpszName;
return;
}
VOID MruUpdateMenu(HMENU hMenu)
@ -312,7 +339,7 @@ VOID MruWriteList(VOID)
{
_ASSERT(ppszFiles != NULL); // MRU not initialized
wsprintf(szItemname,_T("File%d"),i+1);
if (ppszFiles[i] != NULL)
if (ppszFiles[i] != NULL) // valid entry
{
WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
}
@ -338,7 +365,7 @@ VOID MruReadList(VOID)
wsprintf(szItemname,_T("File%d"),i+1);
ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename));
if (ppszFiles[i] != NULL) // already filled
if (ppszFiles[i] != NULL) // valid entry
{
free(ppszFiles[i]); // free entry
ppszFiles[i] = NULL; // clear last line

View file

@ -51,6 +51,7 @@
#endif
#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier
#define __unaligned
#define SetWindowLongPtr SetWindowLong
#define GetWindowLongPtr GetWindowLong
#define SetClassLongPtr SetClassLong

View file

@ -93,6 +93,11 @@ static DWORD WINAPI EventThread(LPVOID pParam)
UNREFERENCED_PARAMETER(pParam);
}
BOOL CommIsOpen(VOID)
{
return hComm != NULL; // have COM port handle
}
BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
{
COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L };
@ -353,7 +358,7 @@ VOID CommReceive(VOID)
// reject reading if com port is closed and not whole operation
if (hComm && dwBytesRead == 0L) // com port open and buffer empty
{
if (ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
if (ReadFile(hComm,cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
dwBytesRead = 0L;
else // bytes received
nRp = 0; // reset read pointer

340
source/gpl.txt Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.