From 8a54fb0b333a60adbd5ac3c5c7508c4253659dac Mon Sep 17 00:00:00 2001
From: dgis
The command line Convert 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 Convert 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 not imply, that the source file + is in an Emu48 suitable format! +
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.
Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator
- Copyright (C) 2020 Christoph Gießelink
Emu48+ - A 39g+/39gs/40gs/48gII/49g+/50g Emulator
- Copyright (C) 2020 Cyrille de Brebisson
- Additional changes by Bill Graves and Eric Rechlin
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
diff --git a/app/src/main/assets/ReadMe.txt b/app/src/main/assets/ReadMe.txt
index 6180c83..324d1dd 100644
--- a/app/src/main/assets/ReadMe.txt
+++ b/app/src/main/assets/ReadMe.txt
@@ -58,6 +58,11 @@ LINKS
CHANGES
+Version 2.4 (2021-12-08)
+
+- Updated source code from Eric Rechlin's Emu48 version 1.63+ that was merged from Christoph Gießelink's Emu48 version 1.64.
+
+
Version 2.3 (2021-10-19)
- Add an experimental serial port support (via USB OTG).
diff --git a/app/src/main/cpp/core/Emu48.c b/app/src/main/cpp/core/Emu48.c
index d35e267..2bb7880 100644
--- a/app/src/main/cpp/core/Emu48.c
+++ b/app/src/main/cpp/core/Emu48.c
@@ -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)
{
diff --git a/app/src/main/cpp/core/debugger.c b/app/src/main/cpp/core/debugger.c
index 23c93c7..67218f3 100644
--- a/app/src/main/cpp/core/debugger.c
+++ b/app/src/main/cpp/core/debugger.c
@@ -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);
diff --git a/app/src/main/cpp/core/disasm.c b/app/src/main/cpp/core/disasm.c
index 71078e0..f5cbe55 100644
--- a/app/src/main/cpp/core/disasm.c
+++ b/app/src/main/cpp/core/disasm.c
@@ -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;
diff --git a/app/src/main/cpp/core/engine.c b/app/src/main/cpp/core/engine.c
index ce5f343..eaf84a9 100644
--- a/app/src/main/cpp/core/engine.c
+++ b/app/src/main/cpp/core/engine.c
@@ -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;
}
diff --git a/app/src/main/cpp/core/fetch.c b/app/src/main/cpp/core/fetch.c
index 1ac9c0c..e19cdf8 100644
--- a/app/src/main/cpp/core/fetch.c
+++ b/app/src/main/cpp/core/fetch.c
@@ -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_[] =
diff --git a/app/src/main/cpp/core/lodepng.c b/app/src/main/cpp/core/lodepng.c
index ddf11ca..532a21c 100644
--- a/app/src/main/cpp/core/lodepng.c
+++ b/app/src/main/cpp/core/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";
}
diff --git a/app/src/main/cpp/core/lodepng.h b/app/src/main/cpp/core/lodepng.h
index a386459..3e1da92 100644
--- a/app/src/main/cpp/core/lodepng.h
+++ b/app/src/main/cpp/core/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