2021-10-01: Updated to version 1.64

Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
Gwenhael Le Moine 2024-03-19 23:35:31 +01:00
parent 523b8ba30d
commit 8f505d8844
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
19 changed files with 1422 additions and 526 deletions

BIN
Emu48.exe

Binary file not shown.

View file

@ -113,6 +113,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

1238
KML_20.DOC

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
Known bugs and restrictions of Emu48 V1.63
Known bugs and restrictions of Emu48 V1.64
------------------------------------------
- the following I/O bits aren't emulated (incomplete)
@ -47,4 +47,4 @@ Known bugs and restrictions of Emu48 V1.63
- quitting the emulator while programming the flash isn't allowed,
because the content of flash state machine isn't saved so far
09/22/20 (c) by Christoph Gießelink, c dot giesselink at gmx dot de
09/28/21 (c) by Christoph Gießelink, c dot giesselink at gmx dot de

View file

@ -1,3 +1,55 @@
Service Pack 64 for Emu48 Version 1.0
DEBUGGER.C
- bugfix in function EnterBreakpoint(), returned an uninitialized
address value on empty breakpoint edit control
- bugfix in function OnDrawBreakWnd(), fixed highlighted background
color
DISASM.C
- bugfix in function disasm_1() and disasm_8(), fixed decoding of
r=ss, ss=r and rssEX with ss = 5, 6, 7, D, E or F register select
EMU48.C
- changed function OnContextMenu(), when the context menu was
generated from the keyboard it opened at a fix position, now when
the mouse cursor position is inside the client window, at the
mouse cursor position
EMU48.RC
- changed version and copyright
ENGINE.C
- changed function InitAdjustSpeed(), added critical section for
writing reference CPU cycles and reference time
- bugfix in function AdjKeySpeed() and SetSpeed(), removed critical
section handling for initializing CPU slow down, because this
section is locked when the CPU emulation thread already slow down
the CPU speed
FETCH.C
- bugfix in table o81Af2_, o81Af1_ and o81Af0_, replaced o_invalid6
function pointers by their corresponding opcode function
- bugfix in table o12_, o11_ and o10_, replaced o_invalid3 function
pointers by their corresponding opcode function
LODEPNG.C
- changed implementation file to LodePNG version 20210627 with
unmarked typecast patches for x64 compatibility, Copyright (c)
2005-2021 Lode Vandevenne
LODEPNG.H
- changed header file to LodePNG version 20210627
MOPS.C
- bugfix in function ReadT2Acc(), moved critical section because
InitAdjustSpeed() part is already protected
SOUND.C
- bugfix in function SoundOut(), removed critical section handling
because InitAdjustSpeed() is already protected
Service Pack 63 for Emu48 Version 1.0
DISPLAY.C

View file

@ -2893,8 +2893,6 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam,
{
static BP_T *sBp;
DWORD dwAddr;
switch (message)
{
case WM_INITDIALOG:
@ -2913,9 +2911,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);
@ -2947,42 +2944,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);

View file

@ -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;

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");
@ -1742,26 +1742,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
{
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));
}
ptc = pt;
VERIFY(ScreenToClient(hWnd,&ptc)); // convert mouse into client position
}
else // got a mouse position
{
POINT ptc = pt;
// convert mouse into client position
VERIFY(ScreenToClient(hWnd,&ptc));
// in client area not over a button
if (ptc.y >= 0 && !MouseIsButton(ptc.x,ptc.y))
bContextMenu = (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)
{

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 © 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,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 Emulator\0"
VALUE "FileVersion", "1, 6, 3, 0\0"
VALUE "FileVersion", "1, 6, 4, 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, 3, 0\0"
VALUE "ProductVersion", "1, 6, 4, 0\0"
END
END
BLOCK "VarFileInfo"

View file

@ -343,11 +343,16 @@ VOID InitAdjustSpeed(VOID)
if (!bEnableSlow || (!bCpuSlow && !bKeySlow && !bSoundSlow && nOpcSlow == 0))
{
LARGE_INTEGER lTime; // sample timer ticks
EnterCriticalSection(&csSlowLock);
{
// save reference cycles
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lTime);// get timer ticks
dwSpeedRef = lTime.LowPart; // save reference time
}
LeaveCriticalSection(&csSlowLock);
}
return;
}
@ -360,29 +365,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
{
InitAdjustSpeed(); // init variables if necessary
}
bKeySlow = bKey; // save new state
}
LeaveCriticalSection(&csSlowLock);
return;
}
VOID SetSpeed(BOOL bAdjust) // set emulation speed
{
EnterCriticalSection(&csSlowLock);
{
if (bAdjust) // switch to real speed
{
InitAdjustSpeed(); // init variables if necessary
}
bCpuSlow = bAdjust; // save emulation speed
}
LeaveCriticalSection(&csSlowLock);
return;
}

99
Sources/Emu48/EXTERNAL.C Normal file
View file

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

View file

@ -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_[] =

View file

@ -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) {
if(settings->custom_zlib) {
return settings->custom_zlib(out, outsize, in, insize, settings);
} else {
unsigned error;
if(settings->custom_zlib) {
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 {
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";
}

View file

@ -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
*/

View file

@ -1002,9 +1002,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);

View file

@ -504,22 +504,14 @@ 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);
if (bSoundSlow == FALSE)
{
EnterCriticalSection(&csSlowLock);
{
InitAdjustSpeed(); // init variables if necessary
bSoundSlow = TRUE; // CPU slow down
}
LeaveCriticalSection(&csSlowLock);
}
return;
}

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 © 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 |
@ -752,8 +752,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
@ -770,12 +770,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0"
VALUE "FileVersion", "1, 6, 3, 0\0"
VALUE "FileVersion", "1, 6, 4, 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, 3, 0\0"
VALUE "ProductVersion", "1, 6, 4, 0\0"
END
END
BLOCK "VarFileInfo"

View file

@ -67,4 +67,4 @@ Many thanks to Pedro A. Arranda Guti
compatible.
09/17/20 (c) by Christoph Gießelink
09/26/21 (c) by Christoph Gießelink

Binary file not shown.