2021-11-24: Updated to version 63
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
parent
20ce3f59ed
commit
9fb7be9e3d
14 changed files with 360 additions and 190 deletions
BIN
Emu48.dll
BIN
Emu48.dll
Binary file not shown.
BIN
Emu48.exe
BIN
Emu48.exe
Binary file not shown.
20
Emu48.htm
20
Emu48.htm
|
@ -114,6 +114,21 @@ h3 { color:red; font-size:1.1em; }
|
|||
into the native Emu48 ROM format is not necessary any more. You can
|
||||
still use the classic way extracting them from your own calculator.
|
||||
</p>
|
||||
<p>The command line <i>Convert</i> utility delivered with the Emu48
|
||||
program package was originally designed to convert HP48 ROM images
|
||||
files from one of the various used ROM image formats of the 90s to
|
||||
the unpacked format originally used by Emu48. The 2nd important
|
||||
task of this tool is updating the I/O register area with zeros.
|
||||
Most images had been created with a ROM upload program where the
|
||||
I/O register area was mapped over the ROM content and so the ROM
|
||||
image file contain a wrong content at this position. Executing the
|
||||
selftest on a HP38 or a HP48 will report an IROM fail then. To fix
|
||||
this the <i>Convert</i> utility overwrites the I/O register area
|
||||
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!
|
||||
</p>
|
||||
<ul>
|
||||
<li>HP38
|
||||
<p>To upload the ROM of your HP38G, you will need a special aplet
|
||||
|
@ -636,10 +651,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) 2020 Christoph Gießelink</p>
|
||||
<p>Emu48+ - A 39g+/39gs/40gs/48gII/49g+/50g Emulator<br>
|
||||
Copyright (C) 2020 Cyrille de Brebisson<br>
|
||||
Additional changes by Bill Graves and Eric Rechlin</p>
|
||||
Copyright (C) 2021 Christoph Gieß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)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
Service Pack 62+ based on Emu48 Service Pack 63
|
||||
Service Pack 63+ based on Emu48 Service Pack 64
|
||||
|
||||
See CHANGES.TXT in Emu48 for full history.
|
||||
Only changes specifically made to Emu48+ are shown below.
|
||||
|
||||
Service Pack 62+ for Emu48 Version 1.0
|
||||
|
||||
APPLE.C
|
||||
APPLE.H
|
||||
- Moved BEEP2 and RCKBp here to match other Apple opcodes
|
||||
|
|
|
@ -2901,8 +2901,6 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam,
|
|||
{
|
||||
static BP_T *sBp;
|
||||
|
||||
DWORD dwAddr;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
|
@ -2921,9 +2919,8 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam,
|
|||
case IDC_BPREAD: sBp->nType = BP_READ; return TRUE;
|
||||
case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE;
|
||||
case IDOK:
|
||||
if (!GetAddr(hDlg,IDC_ENTERADR,&dwAddr,0xFFFFF,disassembler_symb))
|
||||
if (!GetAddr(hDlg,IDC_ENTERADR,&sBp->dwAddr,0xFFFFF,disassembler_symb))
|
||||
return FALSE;
|
||||
sBp->dwAddr = dwAddr;
|
||||
// no break
|
||||
case IDCANCEL:
|
||||
EndDialog(hDlg,wParam);
|
||||
|
@ -2955,42 +2952,35 @@ static __inline BOOL OnDrawBreakWnd(LPDRAWITEMSTRUCT lpdis)
|
|||
COLORREF crBkColor,crTextColor;
|
||||
HDC hdcMem;
|
||||
HBITMAP hBmpOld;
|
||||
INT i;
|
||||
|
||||
if (lpdis->itemID == -1) // no item in list box
|
||||
return TRUE;
|
||||
|
||||
crBkColor = GetBkColor(lpdis->hDC); // save actual color settings
|
||||
crTextColor = GetTextColor(lpdis->hDC);
|
||||
|
||||
if (lpdis->itemState & ODS_SELECTED) // cursor line
|
||||
{
|
||||
crBkColor = COLOR_NAVY;
|
||||
crTextColor = COLOR_WHITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
crBkColor = COLOR_WHITE;
|
||||
crTextColor = COLOR_BLACK;
|
||||
SetBkColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHT));
|
||||
SetTextColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
}
|
||||
|
||||
// write Text
|
||||
crBkColor = SetBkColor(lpdis->hDC,crBkColor);
|
||||
crTextColor = SetTextColor(lpdis->hDC,crTextColor);
|
||||
|
||||
SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf);
|
||||
ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+17,(int)(lpdis->rcItem.top),
|
||||
ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL);
|
||||
|
||||
SetBkColor(lpdis->hDC,crBkColor);
|
||||
SetBkColor(lpdis->hDC,crBkColor); // restore color settings
|
||||
SetTextColor(lpdis->hDC,crTextColor);
|
||||
|
||||
// draw checkbox
|
||||
i = (INT) SendMessage(lpdis->hwndItem,LB_GETITEMDATA,lpdis->itemID,0);
|
||||
hdcMem = CreateCompatibleDC(lpdis->hDC);
|
||||
_ASSERT(hBmpCheckBox);
|
||||
hBmpOld = (HBITMAP) SelectObject(hdcMem,hBmpCheckBox);
|
||||
|
||||
BitBlt(lpdis->hDC,lpdis->rcItem.left+2,lpdis->rcItem.top+2,
|
||||
11,lpdis->rcItem.bottom - lpdis->rcItem.top,
|
||||
hdcMem,sBreakpoint[i].bEnable ? 0 : 10,0,SRCCOPY);
|
||||
hdcMem,sBreakpoint[lpdis->itemData].bEnable ? 0 : 10,0,SRCCOPY);
|
||||
|
||||
SelectObject(hdcMem,hBmpOld);
|
||||
DeleteDC(hdcMem);
|
||||
|
|
|
@ -425,8 +425,8 @@ static LPTSTR disasm_1 (DWORD *addr, LPTSTR out)
|
|||
fn = read_nibble (addr);
|
||||
c = (fn < 8); // flag for operand register
|
||||
fn = (fn & 7); // get register number
|
||||
if (fn > 4) // illegal opcode
|
||||
break; // no output
|
||||
if (fn > 4) // unsupported opcode
|
||||
fn -= 4; // map to valid scratch register
|
||||
switch (disassembler_mode)
|
||||
{
|
||||
case HP_MNEMONICS:
|
||||
|
@ -457,8 +457,8 @@ static LPTSTR disasm_1 (DWORD *addr, LPTSTR out)
|
|||
fn = read_nibble (addr);
|
||||
c = (fn < 8); // flag for operand register
|
||||
fn = (fn & 7); // get register number
|
||||
if (fn > 4) // illegal opcode
|
||||
break; // no output
|
||||
if (fn > 4) // unsupported opcode
|
||||
fn -= 4; // map to valid scratch register
|
||||
switch (disassembler_mode)
|
||||
{
|
||||
case HP_MNEMONICS:
|
||||
|
@ -680,6 +680,7 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out)
|
|||
{
|
||||
BYTE n;
|
||||
BYTE fn;
|
||||
BYTE rn;
|
||||
LPTSTR p = out;
|
||||
TCHAR c;
|
||||
TCHAR buf[20];
|
||||
|
@ -975,48 +976,49 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out)
|
|||
if (n > 2) // illegal opcode
|
||||
break; // no output
|
||||
c = (TCHAR) read_nibble (addr);
|
||||
if (((int) c & 7) > 4) // illegal opcode
|
||||
break; // no output
|
||||
rn = (c & 7); // get register number
|
||||
c = (c < 8); // flag for operand register
|
||||
if (rn > 4) // unsupported opcode
|
||||
rn -= 4; // map to valid scratch register
|
||||
switch (disassembler_mode)
|
||||
{
|
||||
case HP_MNEMONICS:
|
||||
c = (TCHAR) (c ? _T('A') : _T('C'));
|
||||
if (n == 2)
|
||||
{
|
||||
wsprintf (buf, _T("%cR%dEX.F"), ((int) c < 8) ? _T('A') : _T('C'),
|
||||
(int) c & 7);
|
||||
wsprintf (buf, _T("%cR%dEX.F"), c, rn);
|
||||
}
|
||||
else
|
||||
if (n == 1)
|
||||
{
|
||||
wsprintf (buf, _T("%c=R%d.F"), ((int) c < 8) ? _T('A') : _T('C'),
|
||||
(int) c & 7);
|
||||
wsprintf (buf, _T("%c=R%d.F"), c, rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf (buf, _T("R%d=%c.F"), (int) c & 7,
|
||||
((int) c < 8) ? _T('A') : _T('C'));
|
||||
wsprintf (buf, _T("R%d=%c.F"), rn, c);
|
||||
}
|
||||
p = append_str (out, buf);
|
||||
p = append_tab (out);
|
||||
p = append_field (p, fn);
|
||||
break;
|
||||
case CLASS_MNEMONICS:
|
||||
c = (TCHAR) (c ? _T('a') : _T('c'));
|
||||
p = append_str (out, (n == 2) ? _T("exg") : _T("move"));
|
||||
p = append_field (p, fn);
|
||||
p = append_tab (out);
|
||||
if (n == 1)
|
||||
{
|
||||
wsprintf (buf, _T("r%d"), (int) c & 7);
|
||||
wsprintf (buf, _T("r%d"), rn);
|
||||
p = append_str (p, buf);
|
||||
}
|
||||
else
|
||||
p = append_str (p, ((int) c < 8) ? _T("a") : _T("c"));
|
||||
*p++ = c;
|
||||
p = append_str (p, _T(", "));
|
||||
if (n == 1)
|
||||
p = append_str (p, ((int) c < 8) ? _T("a") : _T("c"));
|
||||
*p++ = c;
|
||||
else
|
||||
{
|
||||
wsprintf (buf, _T("r%d"), (int) c & 7);
|
||||
wsprintf (buf, _T("r%d"), rn);
|
||||
p = append_str (p, buf);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "kml.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#define VERSION "1.62+"
|
||||
#define VERSION "1.63+"
|
||||
|
||||
#ifdef _DEBUG
|
||||
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
|
||||
|
@ -1753,26 +1753,40 @@ static LRESULT OnAbout(VOID)
|
|||
|
||||
static VOID OnContextMenu(LPARAM lParam)
|
||||
{
|
||||
HMENU hMenu;
|
||||
POINT pt,ptc;
|
||||
|
||||
if (GetMenu(hWnd) == NULL) // no main window menu
|
||||
{
|
||||
BOOL bContextMenu = TRUE; // call context menu
|
||||
POINT pt;
|
||||
|
||||
POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position
|
||||
|
||||
if (pt.x == -1 && pt.y == -1) // VK_APPS
|
||||
{
|
||||
pt.x = 15; // open context help at client position 15,15
|
||||
pt.y = 15;
|
||||
VERIFY(ClientToScreen(hWnd,&pt));
|
||||
RECT rc;
|
||||
|
||||
GetCursorPos(&pt); // get current mouse position
|
||||
GetWindowRect(hWnd,&rc); // get position of active window
|
||||
if (PtInRect(&rc,pt)==FALSE) // mouse position outside active window
|
||||
{
|
||||
pt.x = 15; // open context help at client position 15,15
|
||||
pt.y = 15;
|
||||
VERIFY(ClientToScreen(hWnd,&pt));
|
||||
}
|
||||
}
|
||||
else // got a mouse position
|
||||
{
|
||||
POINT ptc = pt;
|
||||
// convert mouse into client position
|
||||
VERIFY(ScreenToClient(hWnd,&ptc));
|
||||
|
||||
// in client area not over a button
|
||||
bContextMenu = (ptc.y >= 0 && !MouseIsButton(ptc.x,ptc.y));
|
||||
}
|
||||
|
||||
ptc = pt;
|
||||
VERIFY(ScreenToClient(hWnd,&ptc)); // convert mouse into client position
|
||||
|
||||
// in client area not over a button
|
||||
if (ptc.y >= 0 && !MouseIsButton(ptc.x,ptc.y))
|
||||
if (bContextMenu) // call the context menu
|
||||
{
|
||||
HMENU hMenu;
|
||||
|
||||
// load the popup menu resource
|
||||
if ((hMenu = LoadMenu(hApp,MAKEINTRESOURCE(IDM_MENU))) != NULL)
|
||||
{
|
||||
|
|
|
@ -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 © 2020 Christoph Gießelink && Sébastien Carlier",
|
||||
LTEXT "Copyright © 2021 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,2,0
|
||||
PRODUCTVERSION 1,6,2,0
|
||||
FILEVERSION 1,6,3,0
|
||||
PRODUCTVERSION 1,6,3,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, 2, 0\0"
|
||||
VALUE "FileVersion", "1, 6, 3, 0\0"
|
||||
VALUE "InternalName", "Emu48+\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2020\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2021\0"
|
||||
VALUE "OriginalFilename", "Emu48.exe\0"
|
||||
VALUE "ProductName", "Emu48+\0"
|
||||
VALUE "ProductVersion", "1, 6, 2, 0\0"
|
||||
VALUE "ProductVersion", "1, 6, 3, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -373,10 +373,15 @@ VOID InitAdjustSpeed(VOID)
|
|||
if (!bEnableSlow || (!bCpuSlow && !bKeySlow && !bSoundSlow && nOpcSlow == 0))
|
||||
{
|
||||
LARGE_INTEGER lTime; // sample timer ticks
|
||||
// save reference cycles
|
||||
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
|
||||
QueryPerformanceCounter(&lTime); // get timer ticks
|
||||
dwSpeedRef = lTime.LowPart; // save reference time
|
||||
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
{
|
||||
// save reference cycles
|
||||
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
|
||||
QueryPerformanceCounter(&lTime);// get timer ticks
|
||||
dwSpeedRef = lTime.LowPart; // save reference time
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -390,29 +395,21 @@ VOID AdjKeySpeed(VOID) // slow down key repeat
|
|||
for (i = 0;i < ARRAYSIZEOF(Chipset.Keyboard_Row) && !bKey;++i)
|
||||
bKey = (Chipset.Keyboard_Row[i] != 0);
|
||||
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
if (bKey) // key pressed
|
||||
{
|
||||
if (bKey) // key pressed
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
}
|
||||
bKeySlow = bKey; // save new state
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
bKeySlow = bKey; // save new state
|
||||
return;
|
||||
}
|
||||
|
||||
VOID SetSpeed(BOOL bAdjust) // set emulation speed
|
||||
{
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
if (bAdjust) // switch to real speed
|
||||
{
|
||||
if (bAdjust) // switch to real speed
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
}
|
||||
bCpuSlow = bAdjust; // save emulation speed
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
bCpuSlow = bAdjust; // save emulation speed
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -345,17 +345,17 @@ static JMPTAB o81Af2_[] =
|
|||
(LPCVOID) o81Af22, F,
|
||||
(LPCVOID) o81Af23, F,
|
||||
(LPCVOID) o81Af24, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o81Af21, F,
|
||||
(LPCVOID) o81Af22, F,
|
||||
(LPCVOID) o81Af23, F,
|
||||
(LPCVOID) o81Af28, F,
|
||||
(LPCVOID) o81Af29, F,
|
||||
(LPCVOID) o81Af2A, F,
|
||||
(LPCVOID) o81Af2B, F,
|
||||
(LPCVOID) o81Af2C, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F
|
||||
(LPCVOID) o81Af29, F,
|
||||
(LPCVOID) o81Af2A, F,
|
||||
(LPCVOID) o81Af2B, F
|
||||
};
|
||||
|
||||
static JMPTAB o81Af1_[] =
|
||||
|
@ -365,17 +365,17 @@ static JMPTAB o81Af1_[] =
|
|||
(LPCVOID) o81Af12, F,
|
||||
(LPCVOID) o81Af13, F,
|
||||
(LPCVOID) o81Af14, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o81Af11, F,
|
||||
(LPCVOID) o81Af12, F,
|
||||
(LPCVOID) o81Af13, F,
|
||||
(LPCVOID) o81Af18, F,
|
||||
(LPCVOID) o81Af19, F,
|
||||
(LPCVOID) o81Af1A, F,
|
||||
(LPCVOID) o81Af1B, F,
|
||||
(LPCVOID) o81Af1C, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F
|
||||
(LPCVOID) o81Af19, F,
|
||||
(LPCVOID) o81Af1A, F,
|
||||
(LPCVOID) o81Af1B, F
|
||||
};
|
||||
|
||||
static JMPTAB o81Af0_[] =
|
||||
|
@ -385,17 +385,17 @@ static JMPTAB o81Af0_[] =
|
|||
(LPCVOID) o81Af02, F,
|
||||
(LPCVOID) o81Af03, F,
|
||||
(LPCVOID) o81Af04, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o81Af01, F,
|
||||
(LPCVOID) o81Af02, F,
|
||||
(LPCVOID) o81Af03, F,
|
||||
(LPCVOID) o81Af08, F,
|
||||
(LPCVOID) o81Af09, F,
|
||||
(LPCVOID) o81Af0A, F,
|
||||
(LPCVOID) o81Af0B, F,
|
||||
(LPCVOID) o81Af0C, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F,
|
||||
(LPCVOID) o_invalid6, F
|
||||
(LPCVOID) o81Af09, F,
|
||||
(LPCVOID) o81Af0A, F,
|
||||
(LPCVOID) o81Af0B, F
|
||||
};
|
||||
|
||||
static JMPTAB o81A_[] =
|
||||
|
@ -625,17 +625,17 @@ static JMPTAB o12_[] =
|
|||
(LPCVOID) o122, F,
|
||||
(LPCVOID) o123, F,
|
||||
(LPCVOID) o124, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o121, F,
|
||||
(LPCVOID) o122, F,
|
||||
(LPCVOID) o123, F,
|
||||
(LPCVOID) o128, F,
|
||||
(LPCVOID) o129, F,
|
||||
(LPCVOID) o12A, F,
|
||||
(LPCVOID) o12B, F,
|
||||
(LPCVOID) o12C, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F
|
||||
(LPCVOID) o129, F,
|
||||
(LPCVOID) o12A, F,
|
||||
(LPCVOID) o12B, F
|
||||
};
|
||||
|
||||
static JMPTAB o11_[] =
|
||||
|
@ -645,17 +645,17 @@ static JMPTAB o11_[] =
|
|||
(LPCVOID) o112, F,
|
||||
(LPCVOID) o113, F,
|
||||
(LPCVOID) o114, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o111, F,
|
||||
(LPCVOID) o112, F,
|
||||
(LPCVOID) o113, F,
|
||||
(LPCVOID) o118, F,
|
||||
(LPCVOID) o119, F,
|
||||
(LPCVOID) o11A, F,
|
||||
(LPCVOID) o11B, F,
|
||||
(LPCVOID) o11C, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F
|
||||
(LPCVOID) o119, F,
|
||||
(LPCVOID) o11A, F,
|
||||
(LPCVOID) o11B, F
|
||||
};
|
||||
|
||||
static JMPTAB o10_[] =
|
||||
|
@ -665,17 +665,17 @@ static JMPTAB o10_[] =
|
|||
(LPCVOID) o102, F,
|
||||
(LPCVOID) o103, F,
|
||||
(LPCVOID) o104, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o101, F,
|
||||
(LPCVOID) o102, F,
|
||||
(LPCVOID) o103, F,
|
||||
(LPCVOID) o108, F,
|
||||
(LPCVOID) o109, F,
|
||||
(LPCVOID) o10A, F,
|
||||
(LPCVOID) o10B, F,
|
||||
(LPCVOID) o10C, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F,
|
||||
(LPCVOID) o_invalid3, F
|
||||
(LPCVOID) o109, F,
|
||||
(LPCVOID) o10A, F,
|
||||
(LPCVOID) o10B, F
|
||||
};
|
||||
|
||||
static JMPTAB o1_[] =
|
||||
|
|
185
source/LODEPNG.C
185
source/LODEPNG.C
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
LodePNG version 20200306
|
||||
LodePNG version 20210627
|
||||
|
||||
Copyright (c) 2005-2020 Lode Vandevenne
|
||||
Copyright (c) 2005-2021 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,7 +44,7 @@ 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 = "20200306";
|
||||
const char* LODEPNG_VERSION_STRING = "20210627";
|
||||
|
||||
/*
|
||||
This source file is built up in the following large parts. The code sections
|
||||
|
@ -299,6 +299,7 @@ static void string_cleanup(char** out) {
|
|||
*out = NULL;
|
||||
}
|
||||
|
||||
/*also appends null termination character*/
|
||||
static char* alloc_string_sized(const char* in, size_t insize) {
|
||||
char* out = (char*)lodepng_malloc(insize + 1);
|
||||
if(out) {
|
||||
|
@ -1260,7 +1261,7 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
|
|||
|
||||
/*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/
|
||||
static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
||||
unsigned btype) {
|
||||
unsigned btype, size_t max_output_size) {
|
||||
unsigned error = 0;
|
||||
HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
|
||||
HuffmanTree tree_d; /*the huffman tree for distance codes*/
|
||||
|
@ -1341,6 +1342,9 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
|
|||
/* TODO: revise error codes 10,11,50: the above comment is no longer valid */
|
||||
ERROR_BREAK(51); /*error, bit pointer jumps past memory*/
|
||||
}
|
||||
if(max_output_size && out->size > max_output_size) {
|
||||
ERROR_BREAK(109); /*error, larger than max size*/
|
||||
}
|
||||
}
|
||||
|
||||
HuffmanTree_cleanup(&tree_ll);
|
||||
|
@ -1398,9 +1402,9 @@ static unsigned lodepng_inflatev(ucvector* out,
|
|||
|
||||
if(BTYPE == 3) return 20; /*error: invalid BTYPE*/
|
||||
else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/
|
||||
else error = inflateHuffmanBlock(out, &reader, BTYPE); /*compression, BTYPE 01 or 10*/
|
||||
|
||||
if(error) return error;
|
||||
else error = inflateHuffmanBlock(out, &reader, BTYPE, settings->max_output_size); /*compression, BTYPE 01 or 10*/
|
||||
if(!error && settings->max_output_size && out->size > settings->max_output_size) error = 109;
|
||||
if(error) break;
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -1421,6 +1425,12 @@ static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize,
|
|||
if(settings->custom_inflate) {
|
||||
unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings);
|
||||
out->allocsize = out->size;
|
||||
if(error) {
|
||||
/*the custom inflate is allowed to have its own error codes, however, we translate it to code 110*/
|
||||
error = 110;
|
||||
/*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/
|
||||
if(settings->max_output_size && out->size > settings->max_output_size) error = 109;
|
||||
}
|
||||
return error;
|
||||
} else {
|
||||
return lodepng_inflatev(out, in, insize, settings);
|
||||
|
@ -2116,7 +2126,9 @@ static unsigned deflate(unsigned char** out, size_t* outsize,
|
|||
const unsigned char* in, size_t insize,
|
||||
const LodePNGCompressSettings* settings) {
|
||||
if(settings->custom_deflate) {
|
||||
return settings->custom_deflate(out, outsize, in, insize, settings);
|
||||
unsigned error = settings->custom_deflate(out, outsize, in, insize, settings);
|
||||
/*the custom deflate is allowed to have its own error codes, however, we translate it to code 111*/
|
||||
return error ? 111 : 0;
|
||||
} else {
|
||||
return lodepng_deflate(out, outsize, in, insize, settings);
|
||||
}
|
||||
|
@ -2213,10 +2225,16 @@ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const uns
|
|||
/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */
|
||||
static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size,
|
||||
const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) {
|
||||
unsigned error;
|
||||
if(settings->custom_zlib) {
|
||||
return settings->custom_zlib(out, outsize, in, insize, settings);
|
||||
error = settings->custom_zlib(out, outsize, in, insize, settings);
|
||||
if(error) {
|
||||
/*the custom zlib is allowed to have its own error codes, however, we translate it to code 110*/
|
||||
error = 110;
|
||||
/*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/
|
||||
if(settings->max_output_size && *outsize > settings->max_output_size) error = 109;
|
||||
}
|
||||
} else {
|
||||
unsigned error;
|
||||
ucvector v = ucvector_init(*out, *outsize);
|
||||
if(expected_size) {
|
||||
/*reserve the memory to avoid intermediate reallocations*/
|
||||
|
@ -2226,8 +2244,8 @@ static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t exp
|
|||
error = lodepng_zlib_decompressv(&v, in, insize, settings);
|
||||
*out = v.data;
|
||||
*outsize = v.size;
|
||||
return error;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
@ -2275,7 +2293,9 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig
|
|||
static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
|
||||
size_t insize, const LodePNGCompressSettings* settings) {
|
||||
if(settings->custom_zlib) {
|
||||
return settings->custom_zlib(out, outsize, in, insize, settings);
|
||||
unsigned error = settings->custom_zlib(out, outsize, in, insize, settings);
|
||||
/*the custom zlib is allowed to have its own error codes, however, we translate it to code 111*/
|
||||
return error ? 111 : 0;
|
||||
} else {
|
||||
return lodepng_zlib_compress(out, outsize, in, insize, settings);
|
||||
}
|
||||
|
@ -2334,13 +2354,14 @@ const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT
|
|||
void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) {
|
||||
settings->ignore_adler32 = 0;
|
||||
settings->ignore_nlen = 0;
|
||||
settings->max_output_size = 0;
|
||||
|
||||
settings->custom_zlib = 0;
|
||||
settings->custom_inflate = 0;
|
||||
settings->custom_context = 0;
|
||||
}
|
||||
|
||||
const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0};
|
||||
const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0, 0};
|
||||
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
||||
|
@ -2872,8 +2893,8 @@ static void LodePNGText_cleanup(LodePNGInfo* info) {
|
|||
|
||||
static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) {
|
||||
size_t i = 0;
|
||||
dest->text_keys = 0;
|
||||
dest->text_strings = 0;
|
||||
dest->text_keys = NULL;
|
||||
dest->text_strings = NULL;
|
||||
dest->text_num = 0;
|
||||
for(i = 0; i != source->text_num; ++i) {
|
||||
CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i]));
|
||||
|
@ -2932,10 +2953,10 @@ static void LodePNGIText_cleanup(LodePNGInfo* info) {
|
|||
|
||||
static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) {
|
||||
size_t i = 0;
|
||||
dest->itext_keys = 0;
|
||||
dest->itext_langtags = 0;
|
||||
dest->itext_transkeys = 0;
|
||||
dest->itext_strings = 0;
|
||||
dest->itext_keys = NULL;
|
||||
dest->itext_langtags = NULL;
|
||||
dest->itext_transkeys = NULL;
|
||||
dest->itext_strings = NULL;
|
||||
dest->itext_num = 0;
|
||||
for(i = 0; i != source->itext_num; ++i) {
|
||||
CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i],
|
||||
|
@ -4093,10 +4114,12 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
case 0:
|
||||
for(i = 0; i != length; ++i) recon[i] = scanline[i];
|
||||
break;
|
||||
case 1:
|
||||
case 1: {
|
||||
size_t j = 0;
|
||||
for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i];
|
||||
for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth];
|
||||
for(i = bytewidth; i != length; ++i, ++j) recon[i] = scanline[i] + recon[j];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
if(precon) {
|
||||
for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i];
|
||||
|
@ -4106,24 +4129,56 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
break;
|
||||
case 3:
|
||||
if(precon) {
|
||||
size_t j = 0;
|
||||
for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u);
|
||||
for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u);
|
||||
/* Unroll independent paths of this predictor. A 6x and 8x version is also possible but that adds
|
||||
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];
|
||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
|
||||
recon[i + 3] = s3 + ((r3 + p3) >> 1u);
|
||||
}
|
||||
} 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];
|
||||
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];
|
||||
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
|
||||
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
|
||||
}
|
||||
}
|
||||
for(; i != length; ++i, ++j) recon[i] = scanline[i] + ((recon[j] + precon[i]) >> 1u);
|
||||
} else {
|
||||
size_t j = 0;
|
||||
for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i];
|
||||
for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u);
|
||||
for(i = bytewidth; i != length; ++i, ++j) recon[i] = scanline[i] + (recon[j] >> 1u);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if(precon) {
|
||||
size_t j = 0;
|
||||
for(i = 0; i != bytewidth; ++i) {
|
||||
recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/
|
||||
}
|
||||
|
||||
/* Unroll independent paths of the paeth predictor. A 6x and 8x version would also be possible but that
|
||||
adds too much code. Whether this actually speeds anything up at all depends on compiler and settings. */
|
||||
/* Unroll independent paths of the paeth predictor. A 6x and 8x version is also possible but that
|
||||
adds too much code. Whether this speeds up anything depends on compiler and settings. */
|
||||
if(bytewidth >= 4) {
|
||||
for(; i + 3 < length; i += 4) {
|
||||
size_t j = i - bytewidth;
|
||||
for(; i + 3 < length; i += 4, j += 4) {
|
||||
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];
|
||||
|
@ -4134,8 +4189,7 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
recon[i + 3] = s3 + paethPredictor(r3, p3, q3);
|
||||
}
|
||||
} else if(bytewidth >= 3) {
|
||||
for(; i + 2 < length; i += 3) {
|
||||
size_t j = i - bytewidth;
|
||||
for(; i + 2 < length; i += 3, j += 3) {
|
||||
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];
|
||||
|
@ -4145,8 +4199,7 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
recon[i + 2] = s2 + paethPredictor(r2, p2, q2);
|
||||
}
|
||||
} else if(bytewidth >= 2) {
|
||||
for(; i + 1 < length; i += 2) {
|
||||
size_t j = i - bytewidth;
|
||||
for(; i + 1 < length; i += 2, j += 2) {
|
||||
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];
|
||||
|
@ -4156,16 +4209,17 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
|
|||
}
|
||||
}
|
||||
|
||||
for(; i != length; ++i) {
|
||||
recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
|
||||
for(; i != length; ++i, ++j) {
|
||||
recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[j]));
|
||||
}
|
||||
} else {
|
||||
size_t j = 0;
|
||||
for(i = 0; i != bytewidth; ++i) {
|
||||
recon[i] = scanline[i];
|
||||
}
|
||||
for(i = bytewidth; i < length; ++i) {
|
||||
for(i = bytewidth; i != length; ++i, ++j) {
|
||||
/*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/
|
||||
recon[i] = (scanline[i] + recon[i - bytewidth]);
|
||||
recon[i] = (scanline[i] + recon[j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -4447,10 +4501,13 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz
|
|||
}
|
||||
|
||||
/*compressed text chunk (zTXt)*/
|
||||
static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
|
||||
static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder,
|
||||
const unsigned char* data, size_t chunkLength) {
|
||||
unsigned error = 0;
|
||||
|
||||
/*copy the object to change parameters in it*/
|
||||
LodePNGDecompressSettings zlibsettings = decoder->zlibsettings;
|
||||
|
||||
unsigned length, string2_begin;
|
||||
char *key = 0;
|
||||
unsigned char* str = 0;
|
||||
|
@ -4473,12 +4530,14 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting
|
|||
if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
|
||||
|
||||
length = (unsigned)chunkLength - string2_begin;
|
||||
zlibsettings.max_output_size = decoder->max_text_size;
|
||||
/*will fail if zlib error, e.g. if length is too small*/
|
||||
error = zlib_decompress(&str, &size, 0, &data[string2_begin],
|
||||
length, zlibsettings);
|
||||
length, &zlibsettings);
|
||||
/*error: compressed text larger than decoder->max_text_size*/
|
||||
if(error && size > zlibsettings.max_output_size) error = 112;
|
||||
if(error) break;
|
||||
error = lodepng_add_text_sized(info, key, (char*)str, size);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4489,11 +4548,14 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting
|
|||
}
|
||||
|
||||
/*international text chunk (iTXt)*/
|
||||
static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
|
||||
static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder,
|
||||
const unsigned char* data, size_t chunkLength) {
|
||||
unsigned error = 0;
|
||||
unsigned i;
|
||||
|
||||
/*copy the object to change parameters in it*/
|
||||
LodePNGDecompressSettings zlibsettings = decoder->zlibsettings;
|
||||
|
||||
unsigned length, begin, compressed;
|
||||
char *key = 0, *langtag = 0, *transkey = 0;
|
||||
|
||||
|
@ -4550,9 +4612,12 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting
|
|||
if(compressed) {
|
||||
unsigned char* str = 0;
|
||||
size_t size = 0;
|
||||
zlibsettings.max_output_size = decoder->max_text_size;
|
||||
/*will fail if zlib error, e.g. if length is too small*/
|
||||
error = zlib_decompress(&str, &size, 0, &data[begin],
|
||||
length, zlibsettings);
|
||||
length, &zlibsettings);
|
||||
/*error: compressed text larger than decoder->max_text_size*/
|
||||
if(error && size > zlibsettings.max_output_size) error = 112;
|
||||
if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size);
|
||||
lodepng_free(str);
|
||||
} else {
|
||||
|
@ -4628,11 +4693,13 @@ static unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, siz
|
|||
return 0; /* OK */
|
||||
}
|
||||
|
||||
static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
|
||||
static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* decoder,
|
||||
const unsigned char* data, size_t chunkLength) {
|
||||
unsigned error = 0;
|
||||
unsigned i;
|
||||
size_t size = 0;
|
||||
/*copy the object to change parameters in it*/
|
||||
LodePNGDecompressSettings zlibsettings = decoder->zlibsettings;
|
||||
|
||||
unsigned length, string2_begin;
|
||||
|
||||
|
@ -4655,9 +4722,12 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSetting
|
|||
if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/
|
||||
|
||||
length = (unsigned)chunkLength - string2_begin;
|
||||
zlibsettings.max_output_size = decoder->max_icc_size;
|
||||
error = zlib_decompress(&info->iccp_profile, &size, 0,
|
||||
&data[string2_begin],
|
||||
length, zlibsettings);
|
||||
length, &zlibsettings);
|
||||
/*error: ICC profile larger than decoder->max_icc_size*/
|
||||
if(error && size > zlibsettings.max_output_size) error = 113;
|
||||
info->iccp_profile_size = (unsigned)size;
|
||||
if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/
|
||||
return error;
|
||||
|
@ -4688,9 +4758,9 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
|
|||
} else if(lodepng_chunk_type_equals(chunk, "tEXt")) {
|
||||
error = readChunk_tEXt(&state->info_png, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "zTXt")) {
|
||||
error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
|
||||
error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "iTXt")) {
|
||||
error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
|
||||
error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "tIME")) {
|
||||
error = readChunk_tIME(&state->info_png, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "pHYs")) {
|
||||
|
@ -4702,7 +4772,7 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
|
|||
} else if(lodepng_chunk_type_equals(chunk, "sRGB")) {
|
||||
error = readChunk_sRGB(&state->info_png, data, chunkLength);
|
||||
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
||||
error = readChunk_iCCP(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
|
||||
error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
} else {
|
||||
/* unhandled chunk is ok (is not an error) */
|
||||
|
@ -4820,13 +4890,13 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
} else if(lodepng_chunk_type_equals(chunk, "zTXt")) {
|
||||
/*compressed text chunk (zTXt)*/
|
||||
if(state->decoder.read_text_chunks) {
|
||||
state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
|
||||
state->error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength);
|
||||
if(state->error) break;
|
||||
}
|
||||
} else if(lodepng_chunk_type_equals(chunk, "iTXt")) {
|
||||
/*international text chunk (iTXt)*/
|
||||
if(state->decoder.read_text_chunks) {
|
||||
state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
|
||||
state->error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength);
|
||||
if(state->error) break;
|
||||
}
|
||||
} else if(lodepng_chunk_type_equals(chunk, "tIME")) {
|
||||
|
@ -4845,7 +4915,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
state->error = readChunk_sRGB(&state->info_png, data, chunkLength);
|
||||
if(state->error) break;
|
||||
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
|
||||
state->error = readChunk_iCCP(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);
|
||||
state->error = readChunk_iCCP(&state->info_png, &state->decoder, 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*/ {
|
||||
|
@ -4871,7 +4941,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
|
|||
if(!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize);
|
||||
}
|
||||
|
||||
if(state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) {
|
||||
if(!state->error && state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) {
|
||||
state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */
|
||||
}
|
||||
|
||||
|
@ -4955,6 +5025,11 @@ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, co
|
|||
lodepng_state_init(&state);
|
||||
state.info_raw.colortype = colortype;
|
||||
state.info_raw.bitdepth = bitdepth;
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
/*disable reading things that this function doesn't output*/
|
||||
state.decoder.read_text_chunks = 0;
|
||||
state.decoder.remember_unknown_chunks = 0;
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
error = lodepng_decode(out, w, h, &state, in, insize);
|
||||
lodepng_state_cleanup(&state);
|
||||
return error;
|
||||
|
@ -4997,6 +5072,8 @@ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) {
|
|||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
settings->read_text_chunks = 1;
|
||||
settings->remember_unknown_chunks = 0;
|
||||
settings->max_text_size = 16777216;
|
||||
settings->max_icc_size = 16777216; /* 16MB is much more than enough for any reasonable ICC profile */
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
settings->ignore_crc = 0;
|
||||
settings->ignore_critical = 0;
|
||||
|
@ -6204,6 +6281,16 @@ const char* lodepng_error_text(unsigned code) {
|
|||
case 106: return "PNG file must have PLTE chunk if color type is palette";
|
||||
case 107: return "color convert from palette mode requested without setting the palette data in it";
|
||||
case 108: return "tried to add more than 256 values to a palette";
|
||||
/*this limit can be configured in LodePNGDecompressSettings*/
|
||||
case 109: return "tried to decompress zlib or deflate data larger than desired max_output_size";
|
||||
case 110: return "custom zlib or inflate decompression failed";
|
||||
case 111: return "custom zlib or deflate compression failed";
|
||||
/*max text size limit can be configured in LodePNGDecoderSettings. This error prevents
|
||||
unreasonable memory consumption when decoding due to impossibly large text sizes.*/
|
||||
case 112: return "compressed text unreasonably large";
|
||||
/*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";
|
||||
}
|
||||
return "unknown error code";
|
||||
}
|
||||
|
|
108
source/LODEPNG.H
108
source/LODEPNG.H
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
LodePNG version 20200306
|
||||
LodePNG version 20210627
|
||||
|
||||
Copyright (c) 2005-2020 Lode Vandevenne
|
||||
Copyright (c) 2005-2021 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
|
||||
|
@ -142,16 +142,24 @@ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h,
|
|||
/*
|
||||
Load PNG from disk, from file with given name.
|
||||
Same as the other decode functions, but instead takes a filename as input.
|
||||
*/
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory.*/
|
||||
unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const char* filename,
|
||||
LodePNGColorType colortype, unsigned bitdepth);
|
||||
|
||||
/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/
|
||||
/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory.*/
|
||||
unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const char* filename);
|
||||
|
||||
/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/
|
||||
/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory.*/
|
||||
unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const char* filename);
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
|
@ -191,17 +199,26 @@ unsigned lodepng_encode24(unsigned char** out, size_t* outsize,
|
|||
/*
|
||||
Converts raw pixel data into a PNG file on disk.
|
||||
Same as the other encode functions, but instead takes a filename as output.
|
||||
|
||||
NOTE: This overwrites existing files without warning!
|
||||
*/
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and encode in-memory.*/
|
||||
unsigned lodepng_encode_file(const char* filename,
|
||||
const unsigned char* image, unsigned w, unsigned h,
|
||||
LodePNGColorType colortype, unsigned bitdepth);
|
||||
|
||||
/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/
|
||||
/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and encode in-memory.*/
|
||||
unsigned lodepng_encode32_file(const char* filename,
|
||||
const unsigned char* image, unsigned w, unsigned h);
|
||||
|
||||
/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/
|
||||
/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and encode in-memory.*/
|
||||
unsigned lodepng_encode24_file(const char* filename,
|
||||
const unsigned char* image, unsigned w, unsigned h);
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
|
@ -223,6 +240,9 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
|
|||
/*
|
||||
Converts PNG file from disk to raw pixel data in memory.
|
||||
Same as the other decode functions, but instead takes a filename as input.
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory.
|
||||
*/
|
||||
unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
|
||||
const std::string& filename,
|
||||
|
@ -243,7 +263,11 @@ unsigned encode(std::vector<unsigned char>& out,
|
|||
/*
|
||||
Converts 32-bit RGBA raw pixel data into a PNG file on disk.
|
||||
Same as the other encode functions, but instead takes a filename as output.
|
||||
|
||||
NOTE: This overwrites existing files without warning!
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory.
|
||||
*/
|
||||
unsigned encode(const std::string& filename,
|
||||
const unsigned char* in, unsigned w, unsigned h,
|
||||
|
@ -270,12 +294,21 @@ struct LodePNGDecompressSettings {
|
|||
unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/
|
||||
unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/
|
||||
|
||||
/*use custom zlib decoder instead of built in one (default: null)*/
|
||||
/*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding,
|
||||
return an error, output a data size > max_output_size and all the data up to that point. This is
|
||||
not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is
|
||||
ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones.
|
||||
Set to 0 to impose no limit (the default).*/
|
||||
size_t max_output_size;
|
||||
|
||||
/*use custom zlib decoder instead of built in one (default: null).
|
||||
Should return 0 if success, any non-0 if error (numeric value not exposed).*/
|
||||
unsigned (*custom_zlib)(unsigned char**, size_t*,
|
||||
const unsigned char*, size_t,
|
||||
const LodePNGDecompressSettings*);
|
||||
/*use custom deflate decoder instead of built in one (default: null)
|
||||
if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate)*/
|
||||
if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate).
|
||||
Should return 0 if success, any non-0 if error (numeric value not exposed).*/
|
||||
unsigned (*custom_inflate)(unsigned char**, size_t*,
|
||||
const unsigned char*, size_t,
|
||||
const LodePNGDecompressSettings*);
|
||||
|
@ -454,30 +487,36 @@ typedef struct LodePNGInfo {
|
|||
unsigned background_b; /*blue component of suggested background color*/
|
||||
|
||||
/*
|
||||
non-international text chunks (tEXt and zTXt)
|
||||
Non-international text chunks (tEXt and zTXt)
|
||||
|
||||
The char** arrays each contain num strings. The actual messages are in
|
||||
text_strings, while text_keys are keywords that give a short description what
|
||||
the actual text represents, e.g. Title, Author, Description, or anything else.
|
||||
|
||||
All the string fields below including keys, names and language tags are null terminated.
|
||||
All the string fields below including strings, keys, names and language tags are null terminated.
|
||||
The PNG specification uses null characters for the keys, names and tags, and forbids null
|
||||
characters to appear in the main text which is why we can use null termination everywhere here.
|
||||
|
||||
A keyword is minimum 1 character and maximum 79 characters long. It's
|
||||
discouraged to use a single line length longer than 79 characters for texts.
|
||||
A keyword is minimum 1 character and maximum 79 characters long (plus the
|
||||
additional null terminator). It's discouraged to use a single line length
|
||||
longer than 79 characters for texts.
|
||||
|
||||
Don't allocate these text buffers yourself. Use the init/cleanup functions
|
||||
correctly and use lodepng_add_text and lodepng_clear_text.
|
||||
|
||||
Standard text chunk keywords and strings are encoded using Latin-1.
|
||||
*/
|
||||
size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/
|
||||
char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/
|
||||
char** text_strings; /*the actual text*/
|
||||
|
||||
/*
|
||||
international text chunks (iTXt)
|
||||
International text chunks (iTXt)
|
||||
Similar to the non-international text chunks, but with additional strings
|
||||
"langtags" and "transkeys".
|
||||
"langtags" and "transkeys", and the following text encodings are used:
|
||||
keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8.
|
||||
keys must be 1-79 characters (plus the additional null terminator), the other
|
||||
strings are any length.
|
||||
*/
|
||||
size_t itext_num; /*the amount of international texts in this PNG*/
|
||||
char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/
|
||||
|
@ -639,8 +678,19 @@ typedef struct LodePNGDecoderSettings {
|
|||
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/
|
||||
|
||||
/*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/
|
||||
unsigned remember_unknown_chunks;
|
||||
|
||||
/* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned,
|
||||
unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size.
|
||||
By default it is a value that prevents unreasonably large strings from hogging memory. */
|
||||
size_t max_text_size;
|
||||
|
||||
/* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to
|
||||
0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any
|
||||
legitimate profile could be to hog memory. */
|
||||
size_t max_icc_size;
|
||||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
} LodePNGDecoderSettings;
|
||||
|
||||
|
@ -950,6 +1000,9 @@ out: output parameter, contains pointer to loaded buffer.
|
|||
outsize: output parameter, size of the allocated out buffer
|
||||
filename: the path to the file to load
|
||||
return value: error code (0 means ok)
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory.
|
||||
*/
|
||||
unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename);
|
||||
|
||||
|
@ -960,6 +1013,9 @@ buffer: the buffer to write
|
|||
buffersize: size of the buffer to write
|
||||
filename: the path to the file to save to
|
||||
return value: error code (0 means ok)
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and encode in-memory
|
||||
*/
|
||||
unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename);
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
|
@ -1000,12 +1056,18 @@ unsigned encode(std::vector<unsigned char>& out,
|
|||
/*
|
||||
Load a file from disk into an std::vector.
|
||||
return value: error code (0 means ok)
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and decode in-memory
|
||||
*/
|
||||
unsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename);
|
||||
|
||||
/*
|
||||
Save the binary data in an std::vector to a file on disk. The file is overwritten
|
||||
without warning.
|
||||
|
||||
NOTE: Wide-character filenames are not supported, you can use an external method
|
||||
to handle such files and encode in-memory
|
||||
*/
|
||||
unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename);
|
||||
#endif /* LODEPNG_COMPILE_DISK */
|
||||
|
@ -1505,6 +1567,11 @@ of the error in English as a string.
|
|||
|
||||
Check the implementation of lodepng_error_text to see the meaning of each code.
|
||||
|
||||
It is not recommended to use the numerical values to programmatically make
|
||||
different decisions based on error types as the numbers are not guaranteed to
|
||||
stay backwards compatible. They are for human consumption only. Programmatically
|
||||
only 0 or non-0 matter.
|
||||
|
||||
|
||||
8. chunks and PNG editing
|
||||
-------------------------
|
||||
|
@ -1678,6 +1745,9 @@ try to fix it if the compiler is modern and standards compliant.
|
|||
This decoder example shows the most basic usage of LodePNG. More complex
|
||||
examples can be found on the LodePNG website.
|
||||
|
||||
NOTE: these examples do not support wide-character filenames, you can use an
|
||||
external method to handle such files and encode or decode in-memory
|
||||
|
||||
10.1. decoder C++ example
|
||||
-------------------------
|
||||
|
||||
|
@ -1775,6 +1845,10 @@ symbol.
|
|||
Not all changes are listed here, the commit history in github lists more:
|
||||
https://github.com/lvandeve/lodepng
|
||||
|
||||
*) 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).
|
||||
*) 17 okt 2020: prevent decoding too large text/icc chunks by default.
|
||||
*) 06 mar 2020: simplified some of the dynamic memory allocations.
|
||||
*) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct
|
||||
overflow checks.
|
||||
|
@ -1941,5 +2015,5 @@ Domain: gmail dot com.
|
|||
Account: lode dot vandevenne.
|
||||
|
||||
|
||||
Copyright (c) 2005-2020 Lode Vandevenne
|
||||
Copyright (c) 2005-2021 Lode Vandevenne
|
||||
*/
|
||||
|
|
|
@ -1009,9 +1009,9 @@ static DWORD ReadT2Acc(VOID)
|
|||
// maybe CPU speed measurement, slow down the next 10 CPU opcodes
|
||||
if (dwCycDif < 150)
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
nOpcSlow = 10; // slow down next 10 opcodes
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
|
|
|
@ -504,21 +504,13 @@ VOID SoundOut(CHIPSET* w, WORD wOut)
|
|||
}
|
||||
|
||||
// ran out of buffers -> disable CPU slow down
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
bEnableSlow = (GetSoundBufSize() > 1);
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
bEnableSlow = (GetSoundBufSize() > 1);
|
||||
|
||||
if (bSoundSlow == FALSE)
|
||||
{
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
bSoundSlow = TRUE; // CPU slow down
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
bSoundSlow = TRUE; // CPU slow down
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue