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.
This commit is contained in:
dgis 2021-12-12 09:48:47 +01:00
parent 1b26b74f48
commit 8a54fb0b33
14 changed files with 365 additions and 187 deletions

View file

@ -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).
@ -251,7 +256,7 @@ TODO
BUILD
Emu48 for Android is built with Android Studio 4.1 (2020).
Emu48 for Android is built with Android Studio 2020.3.1 (2021).
And to generate an installable APK file with a real Android device, it MUST be signed.
Either use Android Studio:

View file

@ -33,8 +33,8 @@ android {
applicationId "org.emulator.forty.eight"
minSdkVersion 19
targetSdkVersion 30
versionCode 22
versionName "2.3"
versionCode 23
versionName "2.4"
setProperty("archivesBaseName", "Emu48-v$versionName")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {

View file

@ -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&szlig;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&szlig;elink</p>
<p>This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)

View file

@ -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).

View file

@ -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)
{

View file

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

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

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

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) {
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";
}

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

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

View file

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

View file

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
classpath 'com.android.tools.build:gradle:7.0.4'
// NOTE: Do not place your application dependencies here; they belong