diff --git a/README.md b/README.md new file mode 100644 index 0000000..169c1dd --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# XTBook: MediaWiki Viewer for Sharp Brain + +![](XTBook-en.png)
+© Wikipedia "[Wikipedia](https://en.wikipedia.org/wiki/Wikipedia)" - [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +[XTBook](https://www.nexhawks.net/) is a piece of software developed by [Nexhawks](https://github.com/yvt) and allows you to browse MediaWiki-based wiki sites on [SHARP Brain](https://jp.sharp/edictionary/) series electronic dictionaries, Windows PCs, Linux, and Mac. It supports Wikiplexus formatted data generated from a dump file of a MediaWiki-based wiki site and Image-Complex formatted data generated from image files. Also, XTBook can search articles in a second from more than 1,000,000 keys by using a searching database embedded in XTBook Wikiplexus. + +**Concepts** + +- Processes a wiki site in the same procedure as Wikipedia as much as possible +- Prioritizes processing accuracy +- Supports JPEG and HTML + +## How To Use Our Dictionary Files + +Download desired wikis from [Releases](../../releases), and follow instructions at [our project wiki (Japanese)](../../wiki). You can also learn how to make dictionary files by yourself there. + +## How To Obtain the XTBook Itself + +You can download the original distribution by Nexhawks [here](https://github.com/yvt/xtbook/releases). Also, I made another version with small fixes such as avoiding the usage of `gets()` and updating libraries [here](https://github.com/watamario15/xtbook/releases/tag/v0.2.7). Mac (x86 32-bit) version is only on the original release, and Linux (x86 64-bit) version is only on my release. + +## Previous Repository at OSDN + +In response to the current outage of OSDN, we moved the distribution site of dictionary files to this GitHub repository. You can still download old files from mirror sites such as followings while the [main OSDN site](https://osdn.net/projects/xtbook/) is unavailable. + +**JAIST** + +- Release: https://jaist.dl.sourceforge.jp/xtbook/ +- Storage: https://jaist.dl.sourceforge.jp/storage/g/x/xt/xtbook/ + +**IIJ** + +- Release: https://iij.dl.sourceforge.jp/xtbook/ +- Storage: https://iij.dl.sourceforge.jp/storage/g/x/xt/xtbook/ + +## Images + +You can use [jawikiimg-20190730.xtbdict.7z](https://iij.dl.sourceforge.jp/storage/g/x/xt/xtbook/WikipediaImage/20190730/jawikiimg-20190730.xtbdict.7z) for Japanese Wikipedia. For other wiki sites, you may find an image distribution in an older release. + +## Licenses + +Refer to the bottom of [our project wiki](../../wiki) or [our web page](https://watamario15.github.io/xtbook/). Note that images contain files that are under a different license, as described [here](https://dumps.wikimedia.org/legal.html) for Wikipedia. + +--- + +# 【XTBook】SHARP Brain 用 MediaWiki ビューア + +![](XTBook-ja.png)
+© Wikipedia "[ウィキペディア](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A3%E3%82%AD%E3%83%9A%E3%83%87%E3%82%A3%E3%82%A2)" - [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +[XTBook](https://www.nexhawks.net/) は [Nexhawks 氏](https://github.com/yvt)が[電子辞書 SHARP Brain](https://jp.sharp/edictionary/)、Windows PC、Linux、Mac で MediaWiki を可能な限り原版に忠実な形で表示するために開発したアプリケーションです。MediaWiki のダンプデータを変換して生成される、XTBook Wikiplexus 形式及び画像を変換した Image Complex 形式のデータベースに対応します。 また、XTBook Wikiplexus に内蔵された検索データベースを利用し、1,000,000 件以上のキーから高速に検索をすることができます。 + +**コンセプト** + +- 可能な限り通常の Wikipedia と同じ手順で処理する +- 処理精度を優先する +- JPEG と HTML をサポートする + +## 配布辞書ファイルの使い方 + +欲しい wiki のデータを [Releases](../../releases) からダウンロードしたのち、[このプロジェクトの wiki](../../wiki) の説明に従ってください。この wiki では、辞書ファイルの自作方法も扱っています。 + +## XTBook 本体の入手方法 + +Nexhawks 氏の公式版は[こちら](https://github.com/yvt/xtbook/releases)から入手できます。私が `gets()` の回避、ライブラリの更新などの微細な変更を行った版は[こちら](https://github.com/watamario15/xtbook/releases/tag/v0.2.7)から入手できます。Mac (x86 32-bit) 版は公式リリース、Linux (x86 64-bit) 版は私のリリースのみで提供されています。 + +## 旧 OSDN リポジトリ + +現在発生している OSDN の障害に対処するため、XTBook 辞書ファイルの配布を本 GitHub リポジトリに完全移行しました。以前のファイルは、以下のミラーサイトからダウンロードしてください。 + +**JAIST** + +- Release: https://jaist.dl.sourceforge.jp/xtbook/ +- Storage: https://jaist.dl.sourceforge.jp/storage/g/x/xt/xtbook/ + +**IIJ** + +- Release: https://iij.dl.sourceforge.jp/xtbook/ +- Storage: https://iij.dl.sourceforge.jp/storage/g/x/xt/xtbook/ + +## 画像データ + +日本語版 Wikipedia は [jawikiimg-20190730.xtbdict.7z](https://iij.dl.sourceforge.jp/storage/g/x/xt/xtbook/WikipediaImage/20190730/jawikiimg-20190730.xtbdict.7z) を使用してください。他の Wiki に関しては、最新版リリースに含まれていなくても古いリリースには含まれている場合があります。 + +## ライセンス + +[プロジェクトの wiki](../../wiki) もしくは [Web サイト](https://watamario15.github.io/xtbook/) の下部を参照してください。画像については、例えば Wikipedia であれば[こちら](https://dumps.wikimedia.org/legal.html)で説明されているように、異なるライセンスの画像が含まれていることに注意してください。 diff --git a/RichgelJpeg/H2v2.cpp b/RichgelJpeg/H2v2.cpp deleted file mode 100644 index 6ba306c..0000000 --- a/RichgelJpeg/H2v2.cpp +++ /dev/null @@ -1,368 +0,0 @@ -//------------------------------------------------------------------------------ -// h2v2.cpp -// Upsampling/colorspace conversion (H2V2, YCbCr) -// Last updated: Nov. 16, 2000 -// Copyright (C) 1994-2000 Rich Geldreich -// richgel@voicenet.com -// -// This is a popular case, so it's worth seperating out and optimizing a bit. -// If you compile this module with the Intel Compiler, the MMX version will -// automatically be compiled in. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//------------------------------------------------------------------------------ -#include "jpegdecoder.h" -#ifdef __ICL -#include "mmintrin.h" -#endif -//------------------------------------------------------------------------------ -#define FIX(x, b) ((long) ((x) * (1L<<(b)) + 0.5)) -//------------------------------------------------------------------------------ -// YCbCr H2V2 (2x2:1:1, 6 blocks per MCU) to 24-bit RGB -// This case is very popular, so it's important that it's fast. -// If this module is compiled with the Intel Compiler the faster -// MMX specific version will also be available. -// FIXME: Create all-asm version, so Intel Compiler isn't needed. -void jpeg_decoder::H2V2Convert(void) -{ - int row = max_mcu_y_size - mcu_lines_left; - uchar *d0 = scan_line_0; - uchar *d1 = scan_line_1; - uchar *y; - uchar *c; -#ifdef __ICL - // Included here so ICC includes symbol info for these variables - static bool init_flag = false; - static __m64 CRR_MUL; - static __m64 CRR_SUB; - static __m64 CBB_MUL; - static __m64 CBB_SUB; - static __m64 CRG_MUL; - static __m64 CBG_MUL; - static __m64 GC_SUB; - //__m64 rc, gc, bc; - __m64 m0,m1,m2,m3,m4,m5; - __m64 cr, cb, yy, y0, y1, r, g, b, r0, r1, g0, g1, b0, b1; - __m64 rc0, rc1, gc0, gc1, bc0, bc1; - static __m64 zero = 0; -#endif - - if (row < 8) - y = Psample_buf + row * 8; - else - y = Psample_buf + 64*2 + (row & 7) * 8; - - c = Psample_buf + 64*4 + (row >> 1) * 8; - -#ifdef __ICL - if (use_mmx) - { - if (!init_flag) - { - init_flag = true; - - // FIXME: Hardcode these values - CRR_MUL = _m_from_int(FIX(1.402/4, 16)); - CRR_SUB = _m_from_int((int)(127.5*1.402 + .5)); - - CBB_MUL = _m_from_int(FIX(1.772/4, 16)); - CBB_SUB = _m_from_int((int)(127.5*1.772 + .5)); - - CRG_MUL = _m_from_int(FIX(-0.71414/4, 16)); - CBG_MUL = _m_from_int(FIX(-0.34414/4, 16)); - GC_SUB = _m_from_int((int)(127.5*(-0.71414) + 127.5*(-0.34414) + .5)); - - CRR_MUL = _m_punpcklwd(CRR_MUL, CRR_MUL); - CRR_MUL = _m_punpckldq(CRR_MUL, CRR_MUL); - - CRR_SUB = _m_punpcklwd(CRR_SUB, CRR_SUB); - CRR_SUB = _m_punpckldq(CRR_SUB, CRR_SUB); - - CBB_MUL = _m_punpcklwd(CBB_MUL, CBB_MUL); - CBB_MUL = _m_punpckldq(CBB_MUL, CBB_MUL); - - CBB_SUB = _m_punpcklwd(CBB_SUB, CBB_SUB); - CBB_SUB = _m_punpckldq(CBB_SUB, CBB_SUB); - - CRG_MUL = _m_punpcklwd(CRG_MUL, CRG_MUL); - CRG_MUL = _m_punpckldq(CRG_MUL, CRG_MUL); - - CBG_MUL = _m_punpcklwd(CBG_MUL, CBG_MUL); - CBG_MUL = _m_punpckldq(CBG_MUL, CBG_MUL); - - GC_SUB = _m_punpcklwd(GC_SUB, GC_SUB); - GC_SUB = _m_punpckldq(GC_SUB, GC_SUB); - } - - // Mind-bending MMX intrinsics follow... - for (int i = max_mcus_per_row; i > 0; i--) - { - for (int l = 0; l < 2; l++) - { - m2 = _m_from_int(*(int *)(&c[0])); - m3 = _m_from_int(*(int *)(&c[64])); - - cb = m2; - cb = _m_punpcklbw(cb, cb); - cb = _m_psllw(_m_punpcklbw(cb, zero), 2); - - cr = m3; - cr = _m_punpcklbw(cr, cr); - cr = _m_psllw(_m_punpcklbw(cr, zero), 2); - - rc0 = _m_pmulhw(cr, CRR_MUL); - rc0 = _m_psubw(rc0, CRR_SUB); - - bc0 = _m_pmulhw(cb, CBB_MUL); - bc0 = _m_psubw(bc0, CBB_SUB); - - gc0 = _m_pmulhw(cr, CRG_MUL); - m0 = _m_pmulhw(cb, CBG_MUL); - gc0 = _m_paddw(gc0, m0); - gc0 = _m_psubw(gc0, GC_SUB); - //------- - cb = _m_psrlqi(m2, 16); - cb = _m_punpcklbw(cb, cb); - cb = _m_psllw(_m_punpcklbw(cb, zero), 2); - - cr = _m_psrlqi(m3, 16); - cr = _m_punpcklbw(cr, cr); - cr = _m_psllw(_m_punpcklbw(cr, zero), 2); - - rc1 = _m_pmulhw(cr, CRR_MUL); - rc1 = _m_psubw(rc1, CRR_SUB); - - bc1 = _m_pmulhw(cb, CBB_MUL); - bc1 = _m_psubw(bc1, CBB_SUB); - - gc1 = _m_pmulhw(cr, CRG_MUL); - m0 = _m_pmulhw(cb, CBG_MUL); - gc1 = _m_paddw(gc1, m0); - gc1 = _m_psubw(gc1, GC_SUB); - //------------ - yy = *(__m64 *)y; - y0 = _m_punpcklbw(yy, zero); - y1 = _m_punpcklbw(_m_psrlq(yy, 32), zero); - - r0 = _m_paddsw(y0, rc0); - r1 = _m_paddsw(y1, rc1); - g0 = _m_paddsw(y0, gc0); - g1 = _m_paddsw(y1, gc1); - b0 = _m_paddsw(y0, bc0); - b1 = _m_paddsw(y1, bc1); - - r = _m_packuswb(r0, r1); - g = _m_packuswb(g0, g1); - b = _m_packuswb(b0, b1); - //------------ - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpcklwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpcklwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpcklwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)d0 = _m_por(_m_por(m0, m1), m2); - //------------ - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpckhwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpckhwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpckhwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)(d0 + 8) = _m_por(_m_por(m0, m1), m2); - //------------ - r = _m_psrlqi(r, 32); - g = _m_psrlqi(g, 32); - b = _m_psrlqi(b, 32); - - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpcklwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpcklwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpcklwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)(d0 + 16) = _m_por(_m_por(m0, m1), m2); - //------------ - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpckhwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpckhwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpckhwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)(d0 + 24) = _m_por(_m_por(m0, m1), m2); - //------------ - - //------------ - yy = *(__m64 *)(y + 8); - y0 = _m_punpcklbw(yy, zero); - y1 = _m_punpcklbw(_m_psrlq(yy, 32), zero); - - r0 = _m_paddsw(y0, rc0); - r1 = _m_paddsw(y1, rc1); - g0 = _m_paddsw(y0, gc0); - g1 = _m_paddsw(y1, gc1); - b0 = _m_paddsw(y0, bc0); - b1 = _m_paddsw(y1, bc1); - - r = _m_packuswb(r0, r1); - g = _m_packuswb(g0, g1); - b = _m_packuswb(b0, b1); - //------------ - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpcklwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpcklwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpcklwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)d1 = _m_por(_m_por(m0, m1), m2); - //------------ - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpckhwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpckhwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpckhwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)(d1 + 8) = _m_por(_m_por(m0, m1), m2); - //------------ - r = _m_psrlqi(r, 32); - g = _m_psrlqi(g, 32); - b = _m_psrlqi(b, 32); - - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpcklwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpcklwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpcklwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)(d1 + 16) = _m_por(_m_por(m0, m1), m2); - //------------ - m0 = _m_punpcklbw(r, zero); - m0 = _m_punpckhwd(m0, zero); - - m1 = _m_punpcklbw(g, zero); - m1 = _m_punpckhwd(m1, zero); - m1 = _m_psllqi(m1, 8); - - m2 = _m_punpcklbw(b, zero); - m2 = _m_punpckhwd(m2, zero); - m2 = _m_psllqi(m2, 16); - - *(__m64 *)(d1 + 24) = _m_por(_m_por(m0, m1), m2); - //------------ - - d0 += 8*4; - d1 += 8*4; - - c += 4; - - y += 64; - } - - y += 64*6 - 64*2; - c += 64*6 - 8; - } - - _m_empty(); - } - else - { -#endif - - for (int i = max_mcus_per_row; i > 0; i--) - { - for (int l = 0; l < 2; l++) - { - for (int j = 0; j < 8; j += 2) - { - int cb = c[0]; - int cr = c[64]; - - int rc = crr[cr]; - int gc = ((crg[cr] + cbg[cb]) >> 16); - int bc = cbb[cb]; - - int yy = y[j]; - d0[0] = clamp(yy+rc); - d0[1] = clamp(yy+gc); - d0[2] = clamp(yy+bc); - - yy = y[j+1]; - d0[4] = clamp(yy+rc); - d0[5] = clamp(yy+gc); - d0[6] = clamp(yy+bc); - - yy = y[j+8]; - d1[0] = clamp(yy+rc); - d1[1] = clamp(yy+gc); - d1[2] = clamp(yy+bc); - - yy = y[j+8+1]; - d1[4] = clamp(yy+rc); - d1[5] = clamp(yy+gc); - d1[6] = clamp(yy+bc); - - d0 += 8; - d1 += 8; - - c++; - } - y += 64; - } - - y += 64*6 - 64*2; - c += 64*6 - 8; - } - -#ifdef __ICL - } -#endif - -} - diff --git a/RichgelJpeg/README.md b/RichgelJpeg/README.md new file mode 100644 index 0000000..b2b0e2c --- /dev/null +++ b/RichgelJpeg/README.md @@ -0,0 +1,99 @@ +# jpeg-compressor + +A small (~1000 lines), easy to use public domain (or Apache 2.0) C++ class in a single source file [jpge.cpp](https://github.com/orian/jpeg-compressor/blob/master/jpge.cpp) that writes baseline [JPEG](http://en.wikipedia.org/wiki/JPEG) compressed images. It supports grayscale and H1V1/H2V1/H2V2 [chroma subsampling](http://en.wikipedia.org/wiki/Chroma_subsampling) factors, [Libjpeg](http://en.wikipedia.org/wiki/Libjpeg)-compatible quality settings, and is reasonably fast with fairly low (typically less than 64KB) memory consumption. The core compression class consists of a single 890 line C++ file with a small header, along with a couple optional higher-level helper/example functions. The current release supports both single pass [Huffman coding](http://en.wikipedia.org/wiki/Huffman_coding) and more efficient (but slower) two pass coding, makes only a single dynamic memory allocation, and now accepts 32-bit source images. + +The source distribution also includes an optional, completely stand-alone public domain (or Apache 2.0) JPEG decompression class with progressive image support in a single source file [jpgd.cpp](https://github.com/orian/jpeg-compressor/blob/master/jpgd.cpp). It supports both box and linear chroma upsampling, and grayscale or H1V1/H2V1/H1V2/H2V2 chroma upsampling factors. Unlike every other small JPEG decompressor I've seen, this decompressor has been fuzz tested using zzuf and afl, making it resilent against crashing, overwriting memory, or bad memory reads when given accidently or purposely corrupted inputs. Also unlike many other small JPEG decompressors, jpgd.cpp does not require loading the entire image into memory, just single MCU rows at a time (even when doing linear chroma upsampling). This property makes the decompressor useful on small 32-bit microcontrollers. + +The source distribution includes a sample VS2019 Win32/x64 solution and CMakeLists.txt file for compilation with gcc/clang. + +Thanks to Alex Evans for adding several features to jpge (see a [smaller jpg encoder](http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/)). + +## Basic Usage (Compression) + +Include [jpge.h](https://github.com/orian/jpeg-compressor/blob/master/jpge.h) and call one of these helper functions in the "jpge" namespace: +``` cpp +// Writes JPEG image to a file. +// num_channels must be 1 (Y), 3 (RGB), or 4 (RGBA), image pitch must be width*num_channels. +bool compress_image_to_jpeg_file(const char *pFilename, int width, int height, int num_channels, + const uint8 *pImage_data, const params &comp_params = params()); + +// Writes JPEG image to memory buffer. +// On entry, buf_size is the size of the output buffer pointed at by pBuf, which should be at least ~1024 bytes. +// If return value is true, buf_size will be set to the size of the compressed data. +bool compress_image_to_jpeg_file_in_memory(void *pBuf, int &buf_size, int width, int height, int num_channels, + const uint8 *pImage_data, const params &comp_params = params()); +``` +See [tga2jpg.cpp](https://github.com/orian/jpeg-compressor/blob/master/tga2jpg.cpp) for an example usage. This example uses Sean Barrett's [stb_image.c](http://www.nothings.org/stb_image.c) module to load image files. + +You can also call the `jpge::jpeg_encoder class` directly if you need more control over the image source or how/where the output stream is written. + +## Basic Usage (Decompression) + +Include [jpgd.h](https://github.com/orian/jpeg-compressor/blob/master/jpgd.h) and call one of these helper functions in the "jpgd" namespace: + +``` cpp +// Loads a JPEG image from a memory buffer. +// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA). +// On return, width/height will be set to the image's dimensions, and actual_comps will be set +// to either 1 (grayscale) or 3 (RGB). +unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, + int *width, int *height, int *actual_comps, int req_comps, uint32_t flags = 0); + +// Loads a JPEG image from a file. +unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, + int *actual_comps, int req_comps, uint32_t flags = 0); +``` +Just like the compressor, for more control you can directly utilize the jpgd::jpeg_decompressor class, or call the decompress_jpeg_image_from_stream() function. + +The optional flags are: + +`cFlagBoxChromaFiltering`: Uses much faster box filtering on the chroma components, but may lead to artifacts on some images + +`cFlagDisableSIMD`: Do not use SSE2, even if it's been compiled in + +Set the "JPGD_USE_SSE2" macro to 0 to completely disable SSE2 usage during compilation. By default, it's enabled (unless it's x86/x64 gcc and __SSE2__ is not defined). + +jpgd supports a superset of JPEG features utilized by jpge, so it can decompress any file generated by jpge along with most (if not almost all) JPEG files you're likely to encounter in the wild. It supports progressive and baseline sequential JPEG image files and the H1V1, H2V1, H1V2, and H2V2 chroma subsampling factors. + +## Testing + +The source distribution includes a simple example command line tool called "jpge.exe" (or jpge_x64.exe for Win64 systems) that converts images from any format that [stb_image.c](http://www.nothings.org/stb_image.c) supports (such as PNG, TGA, BMP, etc.) to baseline JPEG using the jpeg_encoder class. Its usage is: + bin/jpge source_file.png destination_file.jpg quality_factor +Where quality_factor ranges from 1-100 (higher is better). + +jpge.exe also includes a few other modes for exhaustive testing of the codec (-x option) and JPEG to TGA decompression (-d option) -- see the help text for more info. + +## Licenses + +The license of jpgd.cpp/.h and jpge.cpp/.h is either Public Domain or Apache 2.0. Choose whatever you want. + +The license for the optional file jpgd_idct.h (and ONLY this file) is Copyright 2009 Intel Corporation: + +``Permission is granted to use, copy, distribute and prepare derivative works of this +software for any purpose and without fee, provided, that the above copyright notice +and this statement appear in all copies. Intel makes no representations about the +suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS." +INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY, +INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, +INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not +assume any responsibility for any errors which may appear in this software nor any +responsibility to update it.`` + +(Set JPGD_USE_SSE2 to 0 to completely disable usage of jpgd_idct.h.) + +## Revisions + + - March 25, 2020 - Upgraded jpgd.cpp to latest version (fuzzed, linear chroma upsampling), added CMakeLists.txt, tested with clang/gcc under Linux, upgraded stb_image.h/stb_image_read.h to latest versions. + - v1.04, May 20, 2012 - Fixed double `fclose()` bug in `cfile_stream::close()` reported by Owen Kaluza. (m_pFile should have been set to NULL here. Crap.) Also put jpge.cpp and jpgd.cpp through MSVC 2008's static code analysis and fixed every warning. They where all harmless things, but it's the [right thing to do](http://www.altdevblogaday.com/2011/12/24/static-code-analysis/). + - v1.03, Apr. 16, 2011 - Added jpgd.cpp/.h (derived from my older [http://code.google.com/p/jpgd/](http://code.google.com/p/jpgd/) project), integrated changes from Alex Evans, added support for two pass compression, added more modes/options and timer to example command line app, lots of testing. + - v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in the H2V1 chroma subsampling method jpeg_encoder::load_block_16_8_8(). (This was a last minute addition and there was actually a typo here - the dither rounding factor was 2 when it should have been 1. It turns out that chroma subsample dithering in the H2V1 case typically lowers PSNR even with the intended rounding factor, unlike H2V2.) + - v1.01, Dec. 18, 2010 - Initial stable release + +## History + +This codec was originally written in C and 16-bit x86 asm way back in 1994 for a DOS image viewer. The primary reference was Pennebaker's and Mitchell's book [JPEG: Still Image Data Compression Standard](http://www.amazon.com/JPEG-Compression-Standard-Multimedia-Standards/dp/0442012721/). The original version supported a simple form of adaptive quantization, used a quantized DCT, and two pass Huffman coding. Around 2000 I ported it to C++, but I didn't really have the time to release it until now. + +Note if you're generating texture mipmaps from loaded images, you may be interested in my [imageresampler](http://code.google.com/p/imageresampler/) project. + +For any questions or problems with this code please contact Rich Geldreich at . Here's my [twitter page](http://twitter.com/#!/richgel999). diff --git a/RichgelJpeg/idct.cpp b/RichgelJpeg/idct.cpp deleted file mode 100644 index c93cf49..0000000 --- a/RichgelJpeg/idct.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// -// 2D IDCT -// Derived from an older version of the IJG's JPEG software. -// Downloadable from: www.ijg.org -// This module is going to be replaced with a faster (and -// uncopyrighted) version. -// I am unable to find the original file from which this code was derived. -// I have included the copyright notice included with latest IJG version of this -// module. -// - -/* - * jidctint.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a slow-but-accurate integer implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on an algorithm described in - * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - * The primary algorithm described there uses 11 multiplies and 29 adds. - * We use their alternate method with 12 multiplies and 32 adds. - * The advantage of this method is that no data path contains more than one - * multiplication; this allows a very simple and accurate implementation in - * scaled fixed-point arithmetic, with a minimal number of shifts. - */ - -/*----------------------------------------------------------------------------*/ -#include "jpegdecoder.h" -/*----------------------------------------------------------------------------*/ -#define CONST_BITS 13 -#define PASS1_BITS 2 -#define SCALEDONE ((int32) 1) -#define CONST_SCALE (SCALEDONE << CONST_BITS) -#define FIX(x) ((int32) ((x) * CONST_SCALE + 0.5)) -/*----------------------------------------------------------------------------*/ -#define FIX_0_298631336 ((int32) 2446) /* FIX(0.298631336) */ -#define FIX_0_390180644 ((int32) 3196) /* FIX(0.390180644) */ -#define FIX_0_541196100 ((int32) 4433) /* FIX(0.541196100) */ -#define FIX_0_765366865 ((int32) 6270) /* FIX(0.765366865) */ -#define FIX_0_899976223 ((int32) 7373) /* FIX(0.899976223) */ -#define FIX_1_175875602 ((int32) 9633) /* FIX(1.175875602) */ -#define FIX_1_501321110 ((int32) 12299) /* FIX(1.501321110) */ -#define FIX_1_847759065 ((int32) 15137) /* FIX(1.847759065) */ -#define FIX_1_961570560 ((int32) 16069) /* FIX(1.961570560) */ -#define FIX_2_053119869 ((int32) 16819) /* FIX(2.053119869) */ -#define FIX_2_562915447 ((int32) 20995) /* FIX(2.562915447) */ -#define FIX_3_072711026 ((int32) 25172) /* FIX(3.072711026) */ -/*----------------------------------------------------------------------------*/ -#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> n) -/*----------------------------------------------------------------------------*/ -#define MULTIPLY(var,cnst) ((var) * (cnst)) -/*----------------------------------------------------------------------------*/ -void idct(BLOCK_TYPE *data, uchar *Pdst_ptr) -{ - int32 tmp0, tmp1, tmp2, tmp3; - int32 tmp10, tmp11, tmp12, tmp13; - int32 z1, z2, z3, z4, z5; - register BLOCK_TYPE *dataptr; - int rowctr; - - dataptr = data; - for (rowctr = 8-1; rowctr >= 0; rowctr--) - { - if ((dataptr[1] | dataptr[2] | dataptr[3] | dataptr[4] | - dataptr[5] | dataptr[6] | dataptr[7]) == 0) - { - int16 dcval = (int16) (dataptr[0] << PASS1_BITS); - - dataptr[0] = dcval; - dataptr[1] = dcval; - dataptr[2] = dcval; - dataptr[3] = dcval; - dataptr[4] = dcval; - dataptr[5] = dcval; - dataptr[6] = dcval; - dataptr[7] = dcval; - - dataptr += 8; /* advance pointer to next row */ - continue; - } - - z2 = (int32) dataptr[2]; - z3 = (int32) dataptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); - tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); - tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - - tmp0 = ((int32) dataptr[0] + (int32) dataptr[4]) << CONST_BITS; - tmp1 = ((int32) dataptr[0] - (int32) dataptr[4]) << CONST_BITS; - - tmp10 = tmp0 + tmp3; - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - tmp0 = (int32) dataptr[7]; - tmp1 = (int32) dataptr[5]; - tmp2 = (int32) dataptr[3]; - tmp3 = (int32) dataptr[1]; - - z1 = tmp0 + tmp3; - z2 = tmp1 + tmp2; - z3 = tmp0 + tmp2; - z4 = tmp1 + tmp3; - z5 = MULTIPLY(z3 + z4, FIX_1_175875602); - - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); - z1 = MULTIPLY(z1, - FIX_0_899976223); - z2 = MULTIPLY(z2, - FIX_2_562915447); - z3 = MULTIPLY(z3, - FIX_1_961570560); - z4 = MULTIPLY(z4, - FIX_0_390180644); - - z3 += z5; - z4 += z5; - - tmp0 += z1 + z3; - tmp1 += z2 + z4; - tmp2 += z2 + z3; - tmp3 += z1 + z4; - - dataptr[0] = (int16) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); - dataptr[7] = (int16) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); - dataptr[1] = (int16) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); - dataptr[6] = (int16) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); - dataptr[2] = (int16) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); - dataptr[5] = (int16) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); - dataptr[3] = (int16) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); - dataptr[4] = (int16) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); - - dataptr += 8; - } - - dataptr = data; - for (rowctr = 8-1; rowctr >= 0; rowctr--) - { - int16 i; - - if ((dataptr[8*1] | dataptr[8*2] | dataptr[8*3] | - dataptr[8*4] | dataptr[8*5] | dataptr[8*6] | - dataptr[8*7]) == 0) - { - int16 dcval = (int16) DESCALE((int32) dataptr[0], PASS1_BITS+3); - - if ((dcval += 128) < 0) - dcval = 0; - else if (dcval > 255) - dcval = 255; - - Pdst_ptr[8*0] = (uchar)dcval; - Pdst_ptr[8*1] = (uchar)dcval; - Pdst_ptr[8*2] = (uchar)dcval; - Pdst_ptr[8*3] = (uchar)dcval; - Pdst_ptr[8*4] = (uchar)dcval; - Pdst_ptr[8*5] = (uchar)dcval; - Pdst_ptr[8*6] = (uchar)dcval; - Pdst_ptr[8*7] = (uchar)dcval; - - dataptr++; - Pdst_ptr++; - continue; - } - - z2 = (int32) dataptr[8*2]; - z3 = (int32) dataptr[8*6]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); - tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); - tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - - tmp0 = ((int32) dataptr[8*0] + (int32) dataptr[8*4]) << CONST_BITS; - tmp1 = ((int32) dataptr[8*0] - (int32) dataptr[8*4]) << CONST_BITS; - - tmp10 = tmp0 + tmp3; - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - tmp0 = (int32) dataptr[8*7]; - tmp1 = (int32) dataptr[8*5]; - tmp2 = (int32) dataptr[8*3]; - tmp3 = (int32) dataptr[8*1]; - - z1 = tmp0 + tmp3; - z2 = tmp1 + tmp2; - z3 = tmp0 + tmp2; - z4 = tmp1 + tmp3; - z5 = MULTIPLY(z3 + z4, FIX_1_175875602); - - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); - z1 = MULTIPLY(z1, - FIX_0_899976223); - z2 = MULTIPLY(z2, - FIX_2_562915447); - z3 = MULTIPLY(z3, - FIX_1_961570560); - z4 = MULTIPLY(z4, - FIX_0_390180644); - - z3 += z5; - z4 += z5; - - tmp0 += z1 + z3; - tmp1 += z2 + z4; - tmp2 += z2 + z3; - tmp3 += z1 + z4; - -#define clamp(i) if (i & 0xFF00) i = (((~i) >> 15) & 0xFF); - - i = (int16) DESCALE(tmp10 + tmp3, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*0] = (uchar)i; - - i = (int16) DESCALE(tmp10 - tmp3, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*7] = (uchar)i; - - i = (int16) DESCALE(tmp11 + tmp2, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*1] = (uchar)i; - - i = (int16) DESCALE(tmp11 - tmp2, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*6] = (uchar)i; - - i = (int16) DESCALE(tmp12 + tmp1, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*2] = (uchar)i; - - i = (int16) DESCALE(tmp12 - tmp1, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*5] = (uchar)i; - - i = (int16) DESCALE(tmp13 + tmp0, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*3] = (uchar)i; - - i = (int16) DESCALE(tmp13 - tmp0, CONST_BITS+PASS1_BITS+3) + 128; - clamp(i) - Pdst_ptr[8*4] = (uchar)i; - - dataptr++; - Pdst_ptr++; - } -} -/*----------------------------------------------------------------------------*/ - diff --git a/RichgelJpeg/jpegdecoder.cpp b/RichgelJpeg/jpegdecoder.cpp deleted file mode 100644 index ba6886f..0000000 --- a/RichgelJpeg/jpegdecoder.cpp +++ /dev/null @@ -1,2307 +0,0 @@ -//------------------------------------------------------------------------------ -// jpegdecoder.cpp -// Small JPEG Decoder Library v0.93b -// Last updated: Dec. 28, 2001 -// Copyright (C) 1994-2000 Rich Geldreich -// richgel@voicenet.com -// -// Dec. 19, 2001 - fixed dumb bug in the decode_next_row functions that -// could cause bogus non-zero coefficients from leaking through in rare cases. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//------------------------------------------------------------------------------ -#include "jpegdecoder.h" -#ifndef max -#define max(a,b) (((a)>(b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a)<(b)) ? (a) : (b)) -#endif - -#ifndef TRUE -#define TRUE (1) -#endif - -#ifndef FALSE -#define FALSE (0) -#endif - -//------------------------------------------------------------------------------ -// Coefficients are stored in this sequence in the data stream. -static int ZAG[64] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, -}; -//------------------------------------------------------------------------------ -const int AAN_SCALE_BITS = 14; -const int IFAST_SCALE_BITS = 2; /* fractional bits in scale factors */ -//------------------------------------------------------------------------------ -static int16 aan_scales[64] = -{ - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 -}; -//------------------------------------------------------------------------------ -// Unconditionally frees all allocated blocks. -void jpeg_decoder::free_all_blocks(void) -{ - if (Pstream) - { - Pstream->detach(); - Pstream = NULL; - } - - for (int i = 0; i < JPGD_MAXBLOCKS; i++) - { - free(blocks[i]); - blocks[i] = NULL; - } -} -//------------------------------------------------------------------------------ -// This method handles all errors. -// It could easily be changed to use C++ exceptions. -void jpeg_decoder::terminate(int status) -{ - error_code = status; - - free_all_blocks(); - - longjmp(jmp_state, status); -} -//------------------------------------------------------------------------------ -// Allocate a block of memory-- store block's address in list for -// later deallocation by free_all_blocks(). -void *jpeg_decoder::alloc(int n) -{ - int i; - // Find a free slot. The number of allocated slots will - // always be very low, so a linear search is good enough. - for (i = 0; i < JPGD_MAXBLOCKS; i++) - { - if (blocks[i] == NULL) - break; - } - - if (i == JPGD_MAXBLOCKS) - terminate(JPGD_TOO_MANY_BLOCKS); - - void *q = malloc(n + 8); - - if (q == NULL) - terminate(JPGD_NOTENOUGHMEM); - - memset(q, 0, n + 8); - - blocks[i] = q; - - // Round to qword boundry, to avoid misaligned accesses with MMX code - return ((void *)(((size_t)q + 7) & ~7)); -} -//------------------------------------------------------------------------------ -// Clear buffer to word values. -void jpeg_decoder::word_clear(void *p, ushort c, uint n) -{ - - uchar *ps = (uchar *)p; - - while (n) - { - *ps++ = (uchar)c; - *ps++ = (uchar)(c>>8); - n--; - - - } -} -//------------------------------------------------------------------------------ -// Refill the input buffer. -// This method will sit in a loop until (A) the buffer is full or (B) -// the stream's read() method reports and end of file condition. -void jpeg_decoder::prep_in_buffer(void) -{ - in_buf_left = 0; - Pin_buf_ofs = in_buf; - - if (eof_flag) - return; - -#ifdef SUPPORT_MMX - bool was_mmx_active = mmx_active; - if (mmx_active) - get_bits_2_mmx_deinit(); -#endif - do - { - int bytes_read = Pstream->read(in_buf + in_buf_left, - JPGD_INBUFSIZE - in_buf_left, - &eof_flag); - - if (bytes_read == -1) - terminate(JPGD_STREAM_READ); - - in_buf_left += bytes_read; - } while ((in_buf_left < JPGD_INBUFSIZE) && (!eof_flag)); - - total_bytes_read += in_buf_left; - - word_clear(Pin_buf_ofs + in_buf_left, 0xD9FF, 64); - -#ifdef SUPPORT_MMX - if (was_mmx_active) - get_bits_2_mmx_init(); -#endif -} -//------------------------------------------------------------------------------ -// Read a Huffman code table. -void jpeg_decoder::read_dht_marker(void) -{ - int i, index, count; - uint left; - uchar huff_num[17]; - uchar huff_val[256]; - - left = get_bits_1(16); - - if (left < 2) - terminate(JPGD_BAD_DHT_MARKER); - - left -= 2; - - while (left) - { - index = get_bits_1(8); - - huff_num[0] = 0; - - count = 0; - - for (i = 1; i <= 16; i++) - { - huff_num[i] = get_bits_1(8); - count += huff_num[i]; - } - - if (count > 255) - terminate(JPGD_BAD_DHT_COUNTS); - - for (i = 0; i < count; i++) - huff_val[i] = get_bits_1(8); - - i = 1 + 16 + count; - - if (left < (uint)i) - terminate(JPGD_BAD_DHT_MARKER); - - left -= i; - - if ((index & 0x10) > 0x10) - terminate(JPGD_BAD_DHT_INDEX); - - index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAXHUFFTABLES >> 1); - - if (index >= JPGD_MAXHUFFTABLES) - terminate(JPGD_BAD_DHT_INDEX); - - if (!this->huff_num[index]) - this->huff_num[index] = (uchar *)alloc(17); - - if (!this->huff_val[index]) - this->huff_val[index] = (uchar *)alloc(256); - - memcpy(this->huff_num[index], huff_num, 17); - memcpy(this->huff_val[index], huff_val, 256); - } -} -//------------------------------------------------------------------------------ -// Read a quantization table. -void jpeg_decoder::read_dqt_marker(void) -{ - int n, i, prec; - uint left; - uint temp; - - left = get_bits_1(16); - - if (left < 2) - terminate(JPGD_BAD_DQT_MARKER); - - left -= 2; - - while (left) - { - n = get_bits_1(8); - prec = n >> 4; - n &= 0x0F; - - if (n >= JPGD_MAXQUANTTABLES) - terminate(JPGD_BAD_DQT_TABLE); - - if (!quant[n]) - quant[n] = (QUANT_TYPE *)alloc(64 * sizeof(QUANT_TYPE)); - - // read quantization entries, in zag order - for (i = 0; i < 64; i++) - { - temp = get_bits_1(8); - - if (prec) - temp = (temp << 8) + get_bits_1(8); - - if (use_mmx_idct) - quant[n][ZAG[i]] = (temp * aan_scales[ZAG[i]] + (1 << (AAN_SCALE_BITS - IFAST_SCALE_BITS - 1))) >> (AAN_SCALE_BITS - IFAST_SCALE_BITS); - else - quant[n][i] = temp; - } - - i = 64 + 1; - - if (prec) - i += 64; - - if (left < (uint)i) - terminate(JPGD_BAD_DQT_LENGTH); - - left -= i; - } -} -//------------------------------------------------------------------------------ -// Read the start of frame (SOF) marker. -void jpeg_decoder::read_sof_marker(void) -{ - int i; - uint left; - - left = get_bits_1(16); - - if (get_bits_1(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */ - terminate(JPGD_BAD_PRECISION); - - image_y_size = get_bits_1(16); - - if ((image_y_size < 1) || (image_y_size > JPGD_MAX_HEIGHT)) - terminate(JPGD_BAD_HEIGHT); - - image_x_size = get_bits_1(16); - - if ((image_x_size < 1) || (image_x_size > JPGD_MAX_WIDTH)) - terminate(JPGD_BAD_WIDTH); - - comps_in_frame = get_bits_1(8); - - if (comps_in_frame > JPGD_MAXCOMPONENTS) - terminate(JPGD_TOO_MANY_COMPONENTS); - - if (left != (uint)(comps_in_frame * 3 + 8)) - terminate(JPGD_BAD_SOF_LENGTH); - - for (i = 0; i < comps_in_frame; i++) - { - comp_ident[i] = get_bits_1(8); - comp_h_samp[i] = get_bits_1(4); - comp_v_samp[i] = get_bits_1(4); - comp_quant[i] = get_bits_1(8); - } -} -//------------------------------------------------------------------------------ -// Used to skip unrecognized markers. -void jpeg_decoder::skip_variable_marker(void) -{ - uint left; - - left = get_bits_1(16); - - if (left < 2) - terminate(JPGD_BAD_VARIABLE_MARKER); - - left -= 2; - - while (left) - { - get_bits_1(8); - left--; - } -} -//------------------------------------------------------------------------------ -// Read a define restart interval (DRI) marker. -void jpeg_decoder::read_dri_marker(void) -{ - if (get_bits_1(16) != 4) - terminate(JPGD_BAD_DRI_LENGTH); - - restart_interval = get_bits_1(16); -} -//------------------------------------------------------------------------------ -// Read a start of scan (SOS) marker. -void jpeg_decoder::read_sos_marker(void) -{ - uint left; - int i, ci, n, c, cc; - - left = get_bits_1(16); - - n = get_bits_1(8); - - comps_in_scan = n; - - left -= 3; - - if ( (left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAXCOMPSINSCAN) ) - terminate(JPGD_BAD_SOS_LENGTH); - - for (i = 0; i < n; i++) - { - cc = get_bits_1(8); - c = get_bits_1(8); - left -= 2; - - for (ci = 0; ci < comps_in_frame; ci++) - if (cc == comp_ident[ci]) - break; - - if (ci >= comps_in_frame) - terminate(JPGD_BAD_SOS_COMP_ID); - - comp_list[i] = ci; - comp_dc_tab[ci] = (c >> 4) & 15; - comp_ac_tab[ci] = (c & 15) + (JPGD_MAXHUFFTABLES >> 1); - } - - spectral_start = get_bits_1(8); - spectral_end = get_bits_1(8); - successive_high = get_bits_1(4); - successive_low = get_bits_1(4); - - if (!progressive_flag) - { - spectral_start = 0; - spectral_end = 63; - } - - left -= 3; - - while (left) /* read past whatever is left */ - { - get_bits_1(8); - left--; - } -} -//------------------------------------------------------------------------------ -// Finds the next marker. -int jpeg_decoder::next_marker(void) -{ - uint c, bytes; - - bytes = 0; - - do - { - do - { - bytes++; - - c = get_bits_1(8); - - } while (c != 0xFF); - - do - { - c = get_bits_1(8); - - } while (c == 0xFF); - - } while (c == 0); - - // If bytes > 0 here, there where extra bytes before the marker (not good). - - return c; -} -//------------------------------------------------------------------------------ -// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is -// encountered. -int jpeg_decoder::process_markers(void) -{ - int c; - - for ( ; ; ) - { - c = next_marker(); - - switch (c) - { - case M_SOF0: - case M_SOF1: - case M_SOF2: - case M_SOF3: - case M_SOF5: - case M_SOF6: - case M_SOF7: -// case M_JPG: - case M_SOF9: - case M_SOF10: - case M_SOF11: - case M_SOF13: - case M_SOF14: - case M_SOF15: - case M_SOI: - case M_EOI: - case M_SOS: - { - return c; - } - case M_DHT: - { - read_dht_marker(); - break; - } - // Sorry, no arithmitic support at this time. Dumb patents! - case M_DAC: - { - terminate(JPGD_NO_ARITHMITIC_SUPPORT); - break; - } - case M_DQT: - { - read_dqt_marker(); - break; - } - case M_DRI: - { - read_dri_marker(); - break; - } - //case M_APP0: /* no need to read the JFIF marker */ - - case M_JPG: - case M_RST0: /* no parameters */ - case M_RST1: - case M_RST2: - case M_RST3: - case M_RST4: - case M_RST5: - case M_RST6: - case M_RST7: - case M_TEM: - { - terminate(JPGD_UNEXPECTED_MARKER); - break; - } - default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ - { - skip_variable_marker(); - break; - } - - } - } -} -//------------------------------------------------------------------------------ -// Finds the start of image (SOI) marker. -// This code is rather defensive: it only checks the first 512 bytes to avoid -// false positives. -void jpeg_decoder::locate_soi_marker(void) -{ - uint lastchar, thischar; - ulong bytesleft; - - lastchar = get_bits_1(8); - - thischar = get_bits_1(8); - - /* ok if it's a normal JPEG file without a special header */ - - if ((lastchar == 0xFF) && (thischar == M_SOI)) - return; - - bytesleft = 512; - - for ( ; ; ) - { - if (--bytesleft == 0) - terminate(JPGD_NOT_JPEG); - - lastchar = thischar; - - thischar = get_bits_1(8); - - if ((lastchar == 0xFF) && (thischar == M_SOI)) - break; - } - - /* Check the next character after marker: if it's not 0xFF, it can't - be the start of the next marker, so it probably isn't a JPEG */ - - thischar = (bit_buf >> 8) & 0xFF; - - if (thischar != 0xFF) - terminate(JPGD_NOT_JPEG); -} -//------------------------------------------------------------------------------ -// Find a start of frame (SOF) marker. -void jpeg_decoder::locate_sof_marker(void) -{ - int c; - - locate_soi_marker(); - - c = process_markers(); - - switch (c) - { - case M_SOF2: - progressive_flag = TRUE; - case M_SOF0: /* baseline DCT */ - case M_SOF1: /* extended sequential DCT */ - { - read_sof_marker(); - break; - } - case M_SOF9: /* Arithmitic coding */ - { - terminate(JPGD_NO_ARITHMITIC_SUPPORT); - break; - } - - default: - { - terminate(JPGD_UNSUPPORTED_MARKER); - break; - } - } -} -//------------------------------------------------------------------------------ -// Find a start of scan (SOS) marker. -int jpeg_decoder::locate_sos_marker(void) -{ - int c; - - c = process_markers(); - - if (c == M_EOI) - return FALSE; - else if (c != M_SOS) - terminate(JPGD_UNEXPECTED_MARKER); - - read_sos_marker(); - - return TRUE; -} -//------------------------------------------------------------------------------ -// Reset everything to default/uninitialized state. -void jpeg_decoder::init(Pjpeg_decoder_stream Pstream, bool use_mmx) -{ - - error_code = 0; - - ready_flag = false; - - image_x_size = image_y_size = 0; - - this->Pstream = Pstream; - -#ifdef SUPPORT_MMX - this->use_mmx = use_mmx; - use_mmx_idct = (use_mmx) && (jpeg_idct_ifast_avail()); -#else - this->use_mmx = false; - use_mmx_idct = false; -#endif - - progressive_flag = FALSE; - - memset(huff_num, 0, sizeof(huff_num)); - memset(huff_val, 0, sizeof(huff_val)); - memset(quant, 0, sizeof(quant)); - - scan_type = 0; - - comps_in_frame = 0; - - memset(comp_h_samp, 0, sizeof(comp_h_samp)); - memset(comp_v_samp, 0, sizeof(comp_v_samp)); - memset(comp_quant, 0, sizeof(comp_quant)); - memset(comp_ident, 0, sizeof(comp_ident)); - memset(comp_h_blocks, 0, sizeof(comp_h_blocks)); - memset(comp_v_blocks, 0, sizeof(comp_v_blocks)); - - comps_in_scan = 0; - memset(comp_list, 0, sizeof(comp_list)); - memset(comp_dc_tab, 0, sizeof(comp_dc_tab)); - memset(comp_ac_tab, 0, sizeof(comp_ac_tab)); - - spectral_start = 0; - spectral_end = 0; - successive_low = 0; - successive_high = 0; - - max_mcu_x_size = 0; - max_mcu_y_size = 0; - - blocks_per_mcu = 0; - max_blocks_per_row = 0; - mcus_per_row = 0; - mcus_per_col = 0; - - memset(mcu_org, 0, sizeof(mcu_org)); - - total_lines_left = 0; - mcu_lines_left = 0; - - real_dest_bytes_per_scan_line = 0; - dest_bytes_per_scan_line = 0; - dest_bytes_per_pixel = 0; - - memset(blocks, 0, sizeof(blocks)); - - memset(h, 0, sizeof(h)); - - memset(dc_coeffs, 0, sizeof(dc_coeffs)); - memset(ac_coeffs, 0, sizeof(ac_coeffs)); - memset(block_y_mcu, 0, sizeof(block_y_mcu)); - - eob_run = 0; - - memset(block_y_mcu, 0, sizeof(block_y_mcu)); - - Pin_buf_ofs = in_buf; - in_buf_left = 0; - eof_flag = false; - tem_flag = 0; - - memset(padd_1, 0, sizeof(padd_1)); - memset(in_buf, 0, sizeof(in_buf)); - memset(padd_2, 0, sizeof(padd_2)); - - restart_interval = 0; - restarts_left = 0; - next_restart_num = 0; - - max_mcus_per_row = 0; - max_blocks_per_mcu = 0; - max_mcus_per_col = 0; - - memset(component, 0, sizeof(component)); - memset(last_dc_val, 0, sizeof(last_dc_val)); - memset(dc_huff_seg, 0, sizeof(dc_huff_seg)); - memset(ac_huff_seg, 0, sizeof(ac_huff_seg)); - memset(block_seg, 0, sizeof(block_seg)); - Psample_buf = NULL; - - total_bytes_read = 0; - - // Tell the stream we're going to use it. - Pstream->attach(); - - use_mmx_getbits = false; - mmx_active = false; - - // Ready the input buffer. - prep_in_buffer(); - - // Prime the bit buffer. - bits_left = 16; - bit_buf_64[0] = 0; - bit_buf_64[1] = 0; - - get_bits_1(16); - get_bits_1(16); - - for (int i = 0; i < JPGD_MAXBLOCKSPERROW; i++) - block_max_zag_set[i] = 64; -} -//------------------------------------------------------------------------------ -#define SCALEBITS 16 -#define ONE_HALF ((long) 1 << (SCALEBITS-1)) -#define FIX(x) ((long) ((x) * (1L<> SCALEBITS; - cbb[i] = ( FIX(1.77200/2) * k + ONE_HALF) >> SCALEBITS; - - crg[i] = (-FIX(0.71414/2)) * k; - cbg[i] = (-FIX(0.34414/2)) * k + ONE_HALF; - } -} -//------------------------------------------------------------------------------ -// This method throws back into the stream any bytes that where read -// into the bit buffer during initial marker scanning. -void jpeg_decoder::fix_in_buffer(void) -{ - /* In case any 0xFF's where pulled into the buffer during marker scanning */ - - if (bits_left == 16) - stuff_char( (uchar)((bit_buf >> 16) & 0xFF)); - - if (bits_left >= 8) - stuff_char( (uchar)((bit_buf >> 24) & 0xFF)); - - stuff_char( (uchar)(bit_buf & 0xFF) ); - - stuff_char( (uchar)((bit_buf >> 8) & 0xFF) ); - -#ifdef SUPPORT_MMX - if (use_mmx_getbits) - { - bits_left = 48; - get_bits_2_mmx_init(); - get_bits_2_mmx(16); - get_bits_2_mmx(16); - get_bits_2_mmx(16); - get_bits_2_mmx(16); - get_bits_2_mmx_deinit(); - } - else -#endif - { - bits_left = 16; - //bit_buf = 0; - get_bits_2(16); - get_bits_2(16); - } -} -//------------------------------------------------------------------------------ -// Performs a 2D IDCT over the entire row's coefficient buffer. -void jpeg_decoder::transform_row(void) -{ -#ifdef SUPPORT_MMX - if (use_mmx_idct) - { - BLOCK_TYPE *Psrc_ptr = block_seg[0]; - uchar *Pdst_ptr = Psample_buf - 8; - - for (int mcu_row = 0; mcu_row < mcus_per_row; mcu_row++) - { - for (int mcu_block = 0; mcu_block < blocks_per_mcu; mcu_block++) - { - int component_id = mcu_org[mcu_block]; - QUANT_TYPE *Pquant_ptr = quant[comp_quant[component_id]]; - - uchar * outptr[8]; - outptr[0] = Pdst_ptr; - outptr[1] = Pdst_ptr+8*1; - outptr[2] = Pdst_ptr+8*2; - outptr[3] = Pdst_ptr+8*3; - outptr[4] = Pdst_ptr+8*4; - outptr[5] = Pdst_ptr+8*5; - outptr[6] = Pdst_ptr+8*6; - outptr[7] = Pdst_ptr+8*7; - - jpeg_idct_ifast( - Psrc_ptr, - Pquant_ptr, - outptr, - 8); - - Psrc_ptr += 64; - Pdst_ptr += 64; - } - } - - jpeg_idct_ifast_deinit(); - } - else -#endif - { - BLOCK_TYPE *Psrc_ptr = block_seg[0]; - uchar *Pdst_ptr = Psample_buf; - - for (int i = max_blocks_per_row; i > 0; i--) - { - // Copy the block to a temp. buffer to prevent the IDCT - // from modifying the entire block. - memcpy(temp_block, Psrc_ptr, 64 * sizeof(BLOCK_TYPE)); - idct(temp_block, Pdst_ptr); - Psrc_ptr += 64; - Pdst_ptr += 64; - } - } -} -//------------------------------------------------------------------------------ -// The coeff_buf series of methods originally stored the coefficients -// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache -// was used to make this process more efficient. Now, we can store the entire -// thing in RAM. -Pcoeff_buf_t jpeg_decoder::coeff_buf_open( - int block_num_x, int block_num_y, - int block_len_x, int block_len_y) -{ - Pcoeff_buf_t cb = (Pcoeff_buf_t)alloc(sizeof(coeff_buf_t)); - - cb->block_num_x = block_num_x; - cb->block_num_y = block_num_y; - - cb->block_len_x = block_len_x; - cb->block_len_y = block_len_y; - - cb->block_size = (block_len_x * block_len_y) * sizeof(BLOCK_TYPE); - - cb->Pdata = (uchar *)alloc(cb->block_size * block_num_x * block_num_y); - - return cb; -} -//------------------------------------------------------------------------------ -void jpeg_decoder::coeff_buf_read( - Pcoeff_buf_t cb, - int block_x, int block_y, - BLOCK_TYPE *buffer) -{ - if (block_x >= cb->block_num_x) - terminate(JPGD_ASSERTION_ERROR); - - if (block_y >= cb->block_num_y) - terminate(JPGD_ASSERTION_ERROR); - - memcpy(buffer, - cb->Pdata + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x), - cb->block_size); -} -//------------------------------------------------------------------------------ -void jpeg_decoder::coeff_buf_write( - Pcoeff_buf_t cb, - int block_x, int block_y, - BLOCK_TYPE *buffer) -{ - if (block_x >= cb->block_num_x) - terminate(JPGD_ASSERTION_ERROR); - - if (block_y >= cb->block_num_y) - terminate(JPGD_ASSERTION_ERROR); - - memcpy(cb->Pdata + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x), - buffer, - cb->block_size); -} -//------------------------------------------------------------------------------ -BLOCK_TYPE *jpeg_decoder::coeff_buf_getp( - Pcoeff_buf_t cb, - int block_x, int block_y) -{ - if (block_x >= cb->block_num_x) - terminate(JPGD_ASSERTION_ERROR); - - if (block_y >= cb->block_num_y) - terminate(JPGD_ASSERTION_ERROR); - - return (BLOCK_TYPE *)(cb->Pdata + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x)); -} -//------------------------------------------------------------------------------ -// Loads and dequantizes the next row of (already decoded) coefficients. -// Progressive images only. -void jpeg_decoder::load_next_row(void) -{ - int i; - BLOCK_TYPE *p; - QUANT_TYPE *q; - int mcu_row, mcu_block, row_block = 0; - int component_num, component_id; - int block_x_mcu[JPGD_MAXCOMPONENTS]; - - memset(block_x_mcu, 0, JPGD_MAXCOMPONENTS * sizeof(int)); - - for (mcu_row = 0; mcu_row < mcus_per_row; mcu_row++) - { - int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; - - for (mcu_block = 0; mcu_block < blocks_per_mcu; mcu_block++) - { - component_id = mcu_org[mcu_block]; - - p = block_seg[row_block]; - q = quant[comp_quant[component_id]]; - - BLOCK_TYPE *pAC = coeff_buf_getp(ac_coeffs[component_id], - block_x_mcu[component_id] + block_x_mcu_ofs, - block_y_mcu[component_id] + block_y_mcu_ofs); - - BLOCK_TYPE *pDC = coeff_buf_getp(dc_coeffs[component_id], - block_x_mcu[component_id] + block_x_mcu_ofs, - block_y_mcu[component_id] + block_y_mcu_ofs); - p[0] = pDC[0]; - memcpy(&p[1], &pAC[1], 63 * sizeof(BLOCK_TYPE)); - - if (!use_mmx_idct) - { - for (i = 63; i > 0; i--) - if (p[ZAG[i]]) - break; - - //block_num[row_block++] = i + 1; - - for ( ; i >= 0; i--) - if (p[ZAG[i]]) - p[ZAG[i]] *= q[i]; - } - - row_block++; - - if (comps_in_scan == 1) - block_x_mcu[component_id]++; - else - { - if (++block_x_mcu_ofs == comp_h_samp[component_id]) - { - block_x_mcu_ofs = 0; - - if (++block_y_mcu_ofs == comp_v_samp[component_id]) - { - block_y_mcu_ofs = 0; - - block_x_mcu[component_id] += comp_h_samp[component_id]; - } - } - } - } - } - - if (comps_in_scan == 1) - block_y_mcu[comp_list[0]]++; - else - { - for (component_num = 0; component_num < comps_in_scan; component_num++) - { - component_id = comp_list[component_num]; - - block_y_mcu[component_id] += comp_v_samp[component_id]; - } - } -} -//------------------------------------------------------------------------------ -// Restart interval processing. -void jpeg_decoder::process_restart(void) -{ - int i, c; - - // Align to a byte boundry - // FIXME: Is this really necessary? get_bits_2() never reads in markers! - //get_bits_2(bits_left & 7); - - // Let's scan a little bit to find the marker, but not _too_ far. - // 1536 is a "fudge factor" that determines how much to scan. - for (i = 1536; i > 0; i--) - if (get_char() == 0xFF) - break; - - if (i == 0) - terminate(JPGD_BAD_RESTART_MARKER); - - for ( ; i > 0; i--) - if ((c = get_char()) != 0xFF) - break; - - if (i == 0) - terminate(JPGD_BAD_RESTART_MARKER); - - // Is it the expected marker? If not, something bad happened. - if (c != (next_restart_num + M_RST0)) - terminate(JPGD_BAD_RESTART_MARKER); - - // Reset each component's DC prediction values. - memset(&last_dc_val, 0, comps_in_frame * sizeof(uint)); - - eob_run = 0; - - restarts_left = restart_interval; - - next_restart_num = (next_restart_num + 1) & 7; - - // Get the bit buffer going again... - -#ifdef SUPPORT_MMX - if (use_mmx_getbits) - { - bits_left = 48; - get_bits_2_mmx(16); - get_bits_2_mmx(16); - get_bits_2_mmx(16); - get_bits_2_mmx(16); - } - else -#endif - { - bits_left = 16; - //bit_buf = 0; - get_bits_2(16); - get_bits_2(16); - } -} -//------------------------------------------------------------------------------ -// Decodes and dequantizes the next row of coefficients. -void jpeg_decoder::decode_next_row(void) -{ - int row_block = 0; - - // Clearing the entire row block buffer can take a lot of time! - // Instead of clearing the entire buffer each row, keep track - // of the number of nonzero entries written to each block and do - // selective clears. - //memset(block_seg[0], 0, mcus_per_row * blocks_per_mcu * 64 * sizeof(BLOCK_TYPE)); - - for (int mcu_row = 0; mcu_row < mcus_per_row; mcu_row++) - { - if ((restart_interval) && (restarts_left == 0)) - process_restart(); - - for (int mcu_block = 0; mcu_block < blocks_per_mcu; mcu_block++) - { - int component_id = mcu_org[mcu_block]; - - BLOCK_TYPE *p = block_seg[row_block]; - QUANT_TYPE *q = quant[comp_quant[component_id]]; - int r, s; - - if ((s = huff_decode(h[comp_dc_tab[component_id]])) != 0) - { - r = get_bits_2(s); - s = HUFF_EXTEND(r, s); - } - - last_dc_val[component_id] = (s += last_dc_val[component_id]); - - if (use_mmx_idct) - p[0] = s; - else - p[0] = s * q[0]; - - int prev_num_set = block_max_zag_set[row_block]; - int k; - Phuff_tables_t Ph = h[comp_ac_tab[component_id]]; - - for (k = 1; k < 64; k++) - { - s = huff_decode(Ph); - - r = s >> 4; - s &= 15; - - if (s) - { - if (r) - { - if ((k + r) > 63) - terminate(JPGD_DECODE_ERROR); - - if (k < prev_num_set) - { - int n = min(r, prev_num_set - k); - int kt = k; - while (n--) - p[ZAG[kt++]] = 0; - } - - k += r; - } - - r = get_bits_2(s); - s = HUFF_EXTEND(r, s); - - //assert(k < 64); - - if (use_mmx_idct) - p[ZAG[k]] = s; - else - p[ZAG[k]] = s * q[k]; - } - else - { - if (r == 15) - { - if ((k + 15) > 63) - terminate(JPGD_DECODE_ERROR); - - if (k < prev_num_set) - { - int n = min(16, prev_num_set - k); //bugfix Dec. 19, 2001 - was 15! - int kt = k; - while (n--) - p[ZAG[kt++]] = 0; - } - - k += 15; - } - else - { - //while (k < 64) - // p[ZAG[k++]] = 0; - - break; - } - } - } - - if (k < prev_num_set) - { - int kt = k; - while (kt < prev_num_set) - p[ZAG[kt++]] = 0; - } - - block_max_zag_set[row_block] = k; - - //block_num[row_block++] = k; - row_block++; - } - - restarts_left--; - } -} -//------------------------------------------------------------------------------ -#ifdef SUPPORT_MMX -void jpeg_decoder::decode_next_row_mmx(void) -{ - int row_block = 0; - - // Clearing the entire row block buffer can take a lot of time! - // Instead of clearing the entire buffer each row, keep track - // of the number of nonzero entries written to each block and do - // selective clears. - //memset(block_seg[0], 0, mcus_per_row * blocks_per_mcu * 64 * sizeof(BLOCK_TYPE)); - - get_bits_2_mmx_init(); - - for (int mcu_row = 0; mcu_row < mcus_per_row; mcu_row++) - { - if ((restart_interval) && (restarts_left == 0)) - process_restart(); - - for (int mcu_block = 0; mcu_block < blocks_per_mcu; mcu_block++) - { - int component_id = mcu_org[mcu_block]; - - BLOCK_TYPE *p = block_seg[row_block]; - QUANT_TYPE *q = quant[comp_quant[component_id]]; - int r, s; - - if ((s = huff_decode_mmx(h[comp_dc_tab[component_id]])) != 0) - { - r = get_bits_2_mmx(s); - s = HUFF_EXTEND(r, s); - } - - last_dc_val[component_id] = (s += last_dc_val[component_id]); - - if (use_mmx_idct) - p[0] = s; - else - p[0] = s * q[0]; - - int prev_num_set = block_max_zag_set[row_block]; - - Phuff_tables_t Ph = h[comp_ac_tab[component_id]]; - - for (int k = 1; k < 64; k++) - { - s = huff_decode_mmx(Ph); - - r = s >> 4; - s &= 15; - - if (s) - { - if (r) - { - if ((k + r) > 63) - terminate(JPGD_DECODE_ERROR); - - if (k < prev_num_set) - { - int n = min(r, prev_num_set - k); - int kt = k; - while (n--) - p[ZAG[kt++]] = 0; - } - - k += r; - } - - r = get_bits_2_mmx(s); - s = HUFF_EXTEND(r, s); - - assert(k < 64); - - if (use_mmx_idct) - p[ZAG[k]] = s; - else - p[ZAG[k]] = s * q[k]; - } - else - { - if (r == 15) - { - if ((k + 15) > 63) - terminate(JPGD_DECODE_ERROR); - - if (k < prev_num_set) - { - int n = min(16, prev_num_set - k); //bugfix Dec. 19, 2001 - was 15! - int kt = k; - while (n--) - p[ZAG[kt++]] = 0; - } - - k += 15; - } - else - break; - } - } - - if (k < prev_num_set) - { - int kt = k; - while (kt < prev_num_set) - p[ZAG[kt++]] = 0; - } - - block_max_zag_set[row_block] = k; - - //block_num[row_block++] = k; - row_block++; - } - - restarts_left--; - } - - get_bits_2_mmx_deinit(); -} -#endif -//------------------------------------------------------------------------------ -// YCbCr H1V1 (1x1:1:1, 3 blocks per MCU) to 24-bit RGB -void jpeg_decoder::H1V1Convert(void) -{ - int row = max_mcu_y_size - mcu_lines_left; - uchar *d = scan_line_0; - uchar *s = Psample_buf + row * 8; - - for (int i = max_mcus_per_row; i > 0; i--) - { - for (int j = 0; j < 8; j++) - { - int y = s[j]; - int cb = s[64+j]; - int cr = s[128+j]; - - d[0] = clamp(y + crr[cr]); - d[1] = clamp(y + ((crg[cr] + cbg[cb]) >> 16)); - d[2] = clamp(y + cbb[cb]); - d += 4; - } - - s += 64*3; - } -} -//------------------------------------------------------------------------------ -// YCbCr H2V1 (2x1:1:1, 4 blocks per MCU) to 24-bit RGB -void jpeg_decoder::H2V1Convert(void) -{ - int row = max_mcu_y_size - mcu_lines_left; - uchar *d0 = scan_line_0; - uchar *y = Psample_buf + row * 8; - uchar *c = Psample_buf + 2*64 + row * 8; - - for (int i = max_mcus_per_row; i > 0; i--) - { - for (int l = 0; l < 2; l++) - { - for (int j = 0; j < 4; j++) - { - int cb = c[0]; - int cr = c[64]; - - int rc = crr[cr]; - int gc = ((crg[cr] + cbg[cb]) >> 16); - int bc = cbb[cb]; - - int yy = y[j<<1]; - d0[0] = clamp(yy+rc); - d0[1] = clamp(yy+gc); - d0[2] = clamp(yy+bc); - - yy = y[(j<<1)+1]; - d0[4] = clamp(yy+rc); - d0[5] = clamp(yy+gc); - d0[6] = clamp(yy+bc); - - d0 += 8; - - c++; - } - y += 64; - } - - y += 64*4 - 64*2; - c += 64*4 - 8; - } -} -//------------------------------------------------------------------------------ -// YCbCr H2V1 (1x2:1:1, 4 blocks per MCU) to 24-bit RGB -void jpeg_decoder::H1V2Convert(void) -{ - int row = max_mcu_y_size - mcu_lines_left; - uchar *d0 = scan_line_0; - uchar *d1 = scan_line_1; - uchar *y; - uchar *c; - - if (row < 8) - y = Psample_buf + row * 8; - else - y = Psample_buf + 64*1 + (row & 7) * 8; - - c = Psample_buf + 64*2 + (row >> 1) * 8; - - for (int i = max_mcus_per_row; i > 0; i--) - { - for (int j = 0; j < 8; j++) - { - int cb = c[0+j]; - int cr = c[64+j]; - - int rc = crr[cr]; - int gc = ((crg[cr] + cbg[cb]) >> 16); - int bc = cbb[cb]; - - int yy = y[j]; - d0[0] = clamp(yy+rc); - d0[1] = clamp(yy+gc); - d0[2] = clamp(yy+bc); - - yy = y[8+j]; - d1[0] = clamp(yy+rc); - d1[1] = clamp(yy+gc); - d1[2] = clamp(yy+bc); - - d0 += 4; - d1 += 4; - } - - y += 64*4; - c += 64*4; - } -} -//------------------------------------------------------------------------------ -// Y (1 block per MCU) to 8-bit greyscale -void jpeg_decoder::GrayConvert(void) -{ - int row = max_mcu_y_size - mcu_lines_left; - uchar *d = scan_line_0; - uchar *s = Psample_buf + row * 8; - - for (int i = max_mcus_per_row; i > 0; i--) - { -#if 0 - d[0] = s[0]; - d[1] = s[1]; - d[2] = s[2]; - d[3] = s[3]; - d[4] = s[4]; - d[5] = s[5]; - d[6] = s[6]; - d[7] = s[7]; -#endif - *(uint *)d = *(uint *)s; - *(uint *)(&d[4]) = *(uint *)(&s[4]); - - s += 64; - d += 8; - } -} -//------------------------------------------------------------------------------ -// Find end of image (EOI) marker, so we can return to the user the -// exact size of the input stream. -void jpeg_decoder::find_eoi(void) -{ - if (!progressive_flag) - { - // Attempt to read the EOI marker. - //get_bits_2(bits_left & 7); - - // Prime the bit buffer - bits_left = 16; - //bit_buf = 0; - get_bits_1(16); - get_bits_1(16); - - // The next marker _should_ be EOI - process_markers(); - } - - total_bytes_read -= in_buf_left; -} -//------------------------------------------------------------------------------ -// Returns the next scan line. -// Returns JPGD_DONE if all scan lines have been returned. -// Returns JPGD_OKAY if a scan line has been returned. -// Returns JPGD_FAILED if an error occured. -int jpeg_decoder::decode( - void * *Pscan_line_ofs, uint *Pscan_line_len) -{ - if ((error_code) || (!ready_flag)) - return (JPGD_FAILED); - - if (total_lines_left == 0) - return (JPGD_DONE); - - if (mcu_lines_left == 0) - { - if (setjmp(jmp_state)) - return (JPGD_DECODE_ERROR); - - if (progressive_flag) - load_next_row(); - else - { -#ifdef SUPPORT_MMX - if (use_mmx_getbits) - decode_next_row_mmx(); - else -#endif - decode_next_row(); - } - - // Find the EOI marker if that was the last row. - if (total_lines_left <= max_mcu_y_size) - find_eoi(); - - transform_row(); - - mcu_lines_left = max_mcu_y_size; - } - - switch (scan_type) - { - case JPGD_YH2V2: - { - if ((mcu_lines_left & 1) == 0) - { - H2V2Convert(); - *Pscan_line_ofs = scan_line_0; - } - else - *Pscan_line_ofs = scan_line_1; - - break; - } - case JPGD_YH2V1: - { - H2V1Convert(); - *Pscan_line_ofs = scan_line_0; - break; - } - case JPGD_YH1V2: - { - if ((mcu_lines_left & 1) == 0) - { - H1V2Convert(); - *Pscan_line_ofs = scan_line_0; - } - else - *Pscan_line_ofs = scan_line_1; - - break; - } - case JPGD_YH1V1: - { - H1V1Convert(); - *Pscan_line_ofs = scan_line_0; - break; - } - case JPGD_GRAYSCALE: - { - GrayConvert(); - *Pscan_line_ofs = scan_line_0; - - break; - } - } - - *Pscan_line_len = real_dest_bytes_per_scan_line; - - mcu_lines_left--; - total_lines_left--; - - return (JPGD_OKAY); -} -//------------------------------------------------------------------------------ -// Creates the tables needed for efficient Huffman decoding. -void jpeg_decoder::make_huff_table( - int index, - Phuff_tables_t hs) -{ - int p, i, l, si; - uchar huffsize[257]; - uint huffcode[257]; - uint code; - uint subtree; - int code_size; - int lastp; - int nextfreeentry; - int currententry; - - p = 0; - - for (l = 1; l <= 16; l++) - { - for (i = 1; i <= huff_num[index][l]; i++) - huffsize[p++] = l; - } - - huffsize[p] = 0; - - lastp = p; - - code = 0; - si = huffsize[0]; - p = 0; - - while (huffsize[p]) - { - while (huffsize[p] == si) - { - huffcode[p++] = code; - code++; - } - - code <<= 1; - si++; - } - - memset(hs->look_up, 0, sizeof(hs->look_up)); - memset(hs->tree, 0, sizeof(hs->tree)); - memset(hs->code_size, 0, sizeof(hs->code_size)); - - nextfreeentry = -1; - - p = 0; - - while (p < lastp) - { - i = huff_val[index][p]; - code = huffcode[p]; - code_size = huffsize[p]; - - hs->code_size[i] = code_size; - - if (code_size <= 8) - { - code <<= (8 - code_size); - - for (l = 1 << (8 - code_size); l > 0; l--) - { - hs->look_up[code] = i; - code++; - } - } - else - { - subtree = (code >> (code_size - 8)) & 0xFF; - - currententry = hs->look_up[subtree]; - - if (currententry == 0) - { - hs->look_up[subtree] = currententry = nextfreeentry; - - nextfreeentry -= 2; - } - - code <<= (16 - (code_size - 8)); - - for (l = code_size; l > 9; l--) - { - if ((code & 0x8000) == 0) - currententry--; - - if (hs->tree[-currententry - 1] == 0) - { - hs->tree[-currententry - 1] = nextfreeentry; - - currententry = nextfreeentry; - - nextfreeentry -= 2; - } - else - currententry = hs->tree[-currententry - 1]; - - code <<= 1; - } - - if ((code & 0x8000) == 0) - currententry--; - - hs->tree[-currententry - 1] = i; - } - - p++; - } -} -//------------------------------------------------------------------------------ -// Verifies the quantization tables needed for this scan are available. -void jpeg_decoder::check_quant_tables(void) -{ - int i; - - for (i = 0; i < comps_in_scan; i++) - if (quant[comp_quant[comp_list[i]]] == NULL) - terminate(JPGD_UNDEFINED_QUANT_TABLE); -} -//------------------------------------------------------------------------------ -// Verifies that all the Huffman tables needed for this scan are available. -void jpeg_decoder::check_huff_tables(void) -{ - int i; - - for (i = 0; i < comps_in_scan; i++) - { - if ((spectral_start == 0) && (huff_num[comp_dc_tab[comp_list[i]]] == NULL)) - terminate(JPGD_UNDEFINED_HUFF_TABLE); - - if ((spectral_end > 0) && (huff_num[comp_ac_tab[comp_list[i]]] == NULL)) - terminate(JPGD_UNDEFINED_HUFF_TABLE); - } - - for (i = 0; i < JPGD_MAXHUFFTABLES; i++) - if (huff_num[i]) - { - if (!h[i]) - h[i] = (Phuff_tables_t)alloc(sizeof(huff_tables_t)); - - make_huff_table(i, h[i]); - } - - for (i = 0; i < blocks_per_mcu; i++) - { - dc_huff_seg[i] = h[comp_dc_tab[mcu_org[i]]]; - ac_huff_seg[i] = h[comp_ac_tab[mcu_org[i]]]; - component[i] = &last_dc_val[mcu_org[i]]; - } -} -//------------------------------------------------------------------------------ -// Determines the component order inside each MCU. -// Also calcs how many MCU's are on each row, etc. -void jpeg_decoder::calc_mcu_block_order(void) -{ - int component_num, component_id; - int max_h_samp = 0, max_v_samp = 0; - - for (component_id = 0; component_id < comps_in_frame; component_id++) - { - if (comp_h_samp[component_id] > max_h_samp) - max_h_samp = comp_h_samp[component_id]; - - if (comp_v_samp[component_id] > max_v_samp) - max_v_samp = comp_v_samp[component_id]; - } - - for (component_id = 0; component_id < comps_in_frame; component_id++) - { - comp_h_blocks[component_id] = ((((image_x_size * comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8; - comp_v_blocks[component_id] = ((((image_y_size * comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8; - } - - if (comps_in_scan == 1) - { - mcus_per_row = comp_h_blocks[comp_list[0]]; - mcus_per_col = comp_v_blocks[comp_list[0]]; - } - else - { - mcus_per_row = (((image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp; - mcus_per_col = (((image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp; - } - - if (comps_in_scan == 1) - { - mcu_org[0] = comp_list[0]; - - blocks_per_mcu = 1; - } - else - { - blocks_per_mcu = 0; - - for (component_num = 0; component_num < comps_in_scan; component_num++) - { - int num_blocks; - - component_id = comp_list[component_num]; - - num_blocks = comp_h_samp[component_id] * comp_v_samp[component_id]; - - while (num_blocks--) - mcu_org[blocks_per_mcu++] = component_id; - } - } -} -//------------------------------------------------------------------------------ -// Starts a new scan. -int jpeg_decoder::init_scan(void) -{ - if (!locate_sos_marker()) - return FALSE; - - calc_mcu_block_order(); - - check_huff_tables(); - - check_quant_tables(); - - memset(last_dc_val, 0, comps_in_frame * sizeof(uint)); - - eob_run = 0; - - if (restart_interval) - { - restarts_left = restart_interval; - next_restart_num = 0; - } - - if ((!progressive_flag) && (use_mmx)) - use_mmx_getbits = true; - - fix_in_buffer(); - - return TRUE; -} -//------------------------------------------------------------------------------ -// Starts a frame. Determines if the number of components or sampling factors -// are supported. -void jpeg_decoder::init_frame(void) -{ - int i; - uchar *q; - - if (comps_in_frame == 1) - { - scan_type = JPGD_GRAYSCALE; - - max_blocks_per_mcu = 1; - - max_mcu_x_size = 8; - max_mcu_y_size = 8; - } - else if (comps_in_frame == 3) - { - if ( ((comp_h_samp[1] != 1) || (comp_v_samp[1] != 1)) || - ((comp_h_samp[2] != 1) || (comp_v_samp[2] != 1)) ) - terminate(JPGD_UNSUPPORTED_SAMP_FACTORS); - - if ((comp_h_samp[0] == 1) && (comp_v_samp[0] == 1)) - { - scan_type = JPGD_YH1V1; - - max_blocks_per_mcu = 3; - - max_mcu_x_size = 8; - max_mcu_y_size = 8; - } - else if ((comp_h_samp[0] == 2) && (comp_v_samp[0] == 1)) - { - scan_type = JPGD_YH2V1; - - max_blocks_per_mcu = 4; - - max_mcu_x_size = 16; - max_mcu_y_size = 8; - } - else if ((comp_h_samp[0] == 1) && (comp_v_samp[0] == 2)) - { - scan_type = JPGD_YH1V2; - - max_blocks_per_mcu = 4; - - max_mcu_x_size = 8; - max_mcu_y_size = 16; - } - else if ((comp_h_samp[0] == 2) && (comp_v_samp[0] == 2)) - { - scan_type = JPGD_YH2V2; - - max_blocks_per_mcu = 6; - - max_mcu_x_size = 16; - max_mcu_y_size = 16; - } - else - terminate(JPGD_UNSUPPORTED_SAMP_FACTORS); - } - else - terminate(JPGD_UNSUPPORTED_COLORSPACE); - - max_mcus_per_row = (image_x_size + (max_mcu_x_size - 1)) / max_mcu_x_size; - max_mcus_per_col = (image_y_size + (max_mcu_y_size - 1)) / max_mcu_y_size; - - /* these values are for the *destination* pixels: after conversion */ - - if (scan_type == JPGD_GRAYSCALE) - dest_bytes_per_pixel = 1; - else - dest_bytes_per_pixel = 4; - - dest_bytes_per_scan_line = ((image_x_size + 15) & 0xFFF0) * dest_bytes_per_pixel; - - real_dest_bytes_per_scan_line = (image_x_size * dest_bytes_per_pixel); - - // Initialize two scan line buffers. - // FIXME: Only the V2 sampling factors need two buffers. - scan_line_0 = (uchar *)alloc(dest_bytes_per_scan_line + 8); - memset(scan_line_0, 0, dest_bytes_per_scan_line); - - scan_line_1 = (uchar *)alloc(dest_bytes_per_scan_line + 8); - memset(scan_line_1, 0, dest_bytes_per_scan_line); - - max_blocks_per_row = max_mcus_per_row * max_blocks_per_mcu; - - // Should never happen - if (max_blocks_per_row > JPGD_MAXBLOCKSPERROW) - terminate(JPGD_ASSERTION_ERROR); - - // Allocate the coefficient buffer, enough for one row's worth of MCU's - q = (uchar *)alloc(max_blocks_per_row * 64 * sizeof(BLOCK_TYPE) + 8); - - // Align to 8-byte boundry, for MMX code - q = (uchar *)(((size_t)q + 7) & ~7); - - // The block_seg[] array's name dates back to the - // 16-bit assembler implementation. "seg" stood for "segment". - for (i = 0; i < max_blocks_per_row; i++) - block_seg[i] = (BLOCK_TYPE *)(q + i * 64 * sizeof(BLOCK_TYPE)); - - for (i = 0; i < max_blocks_per_row; i++) - block_max_zag_set[i] = 64; - - Psample_buf = (uchar *)(((size_t)alloc(max_blocks_per_row * 64 + 8) + 7) & ~7); - - total_lines_left = image_y_size; - - mcu_lines_left = 0; - - create_look_ups(); -} -//------------------------------------------------------------------------------ -// The following methods decode the various types of blocks encountered -// in progressively encoded images. -void progressive_block_decoder::decode_block_dc_first( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y) -{ - int s, r; - BLOCK_TYPE *p = Pd->coeff_buf_getp(Pd->dc_coeffs[component_id], block_x, block_y); - - if ((s = Pd->huff_decode(Pd->h[Pd->comp_dc_tab[component_id]])) != 0) - { - r = Pd->get_bits_2(s); - s = HUFF_EXTEND_P(r, s); - } - - Pd->last_dc_val[component_id] = (s += Pd->last_dc_val[component_id]); - - p[0] = s << Pd->successive_low; -} -//------------------------------------------------------------------------------ -void progressive_block_decoder::decode_block_dc_refine( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y) -{ - if (Pd->get_bits_2(1)) - { - BLOCK_TYPE *p = Pd->coeff_buf_getp(Pd->dc_coeffs[component_id], block_x, block_y); - - p[0] |= (1 << Pd->successive_low); - } -} -//------------------------------------------------------------------------------ -void progressive_block_decoder::decode_block_ac_first( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y) -{ - int k, s, r; - - if (Pd->eob_run) - { - Pd->eob_run--; - return; - } - - BLOCK_TYPE *p = Pd->coeff_buf_getp(Pd->ac_coeffs[component_id], block_x, block_y); - - for (k = Pd->spectral_start; k <= Pd->spectral_end; k++) - { - s = Pd->huff_decode(Pd->h[Pd->comp_ac_tab[component_id]]); - - r = s >> 4; - s &= 15; - - if (s) - { - if ((k += r) > 63) - Pd->terminate(JPGD_DECODE_ERROR); - - r = Pd->get_bits_2(s); - s = HUFF_EXTEND_P(r, s); - - p[ZAG[k]] = s << Pd->successive_low; - } - else - { - if (r == 15) - { - if ((k += 15) > 63) - Pd->terminate(JPGD_DECODE_ERROR); - } - else - { - Pd->eob_run = 1 << r; - - if (r) - Pd->eob_run += Pd->get_bits_2(r); - - Pd->eob_run--; - - break; - } - } - } -} -//------------------------------------------------------------------------------ -void progressive_block_decoder::decode_block_ac_refine( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y) -{ - int s, k, r; - int p1 = 1 << Pd->successive_low; - int m1 = (-1) << Pd->successive_low; - BLOCK_TYPE *p = Pd->coeff_buf_getp(Pd->ac_coeffs[component_id], block_x, block_y); - - k = Pd->spectral_start; - - if (Pd->eob_run == 0) - { - for ( ; k <= Pd->spectral_end; k++) - { - s = Pd->huff_decode(Pd->h[Pd->comp_ac_tab[component_id]]); - - r = s >> 4; - s &= 15; - - if (s) - { - if (s != 1) - Pd->terminate(JPGD_DECODE_ERROR); - - if (Pd->get_bits_2(1)) - s = p1; - else - s = m1; - } - else - { - if (r != 15) - { - Pd->eob_run = 1 << r; - - if (r) - Pd->eob_run += Pd->get_bits_2(r); - - break; - } - } - - do - { - BLOCK_TYPE *this_coef = p + ZAG[k]; - - if (*this_coef != 0) - { - if (Pd->get_bits_2(1)) - { - if ((*this_coef & p1) == 0) - { - if (*this_coef >= 0) - *this_coef += p1; - else - *this_coef += m1; - } - } - } - else - { - if (--r < 0) - break; - } - - k++; - - } while (k <= Pd->spectral_end); - - if ((s) && (k < 64)) - { - p[ZAG[k]] = s; - } - } - } - - if (Pd->eob_run > 0) - { - for ( ; k <= Pd->spectral_end; k++) - { - BLOCK_TYPE *this_coef = p + ZAG[k]; - - if (*this_coef != 0) - { - if (Pd->get_bits_2(1)) - { - if ((*this_coef & p1) == 0) - { - if (*this_coef >= 0) - *this_coef += p1; - else - *this_coef += m1; - } - } - } - } - - Pd->eob_run--; - } -} -//------------------------------------------------------------------------------ -// Decode a scan in a progressively encoded image. -void jpeg_decoder::decode_scan( - Pdecode_block_func decode_block_func) -{ - int mcu_row, mcu_col, mcu_block; - int block_x_mcu[JPGD_MAXCOMPONENTS], block_y_mcu[JPGD_MAXCOMPONENTS]; - - memset(block_y_mcu, 0, sizeof(block_y_mcu)); - - for (mcu_col = 0; mcu_col < mcus_per_col; mcu_col++) - { - int component_num, component_id; - - memset(block_x_mcu, 0, sizeof(block_x_mcu)); - - for (mcu_row = 0; mcu_row < mcus_per_row; mcu_row++) - { - int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; - - if ((restart_interval) && (restarts_left == 0)) - process_restart(); - - for (mcu_block = 0; mcu_block < blocks_per_mcu; mcu_block++) - { - component_id = mcu_org[mcu_block]; - - decode_block_func(this, component_id, - block_x_mcu[component_id] + block_x_mcu_ofs, - block_y_mcu[component_id] + block_y_mcu_ofs); - - if (comps_in_scan == 1) - block_x_mcu[component_id]++; - else - { - if (++block_x_mcu_ofs == comp_h_samp[component_id]) - { - block_x_mcu_ofs = 0; - - if (++block_y_mcu_ofs == comp_v_samp[component_id]) - { - block_y_mcu_ofs = 0; - - block_x_mcu[component_id] += comp_h_samp[component_id]; - } - } - } - } - - restarts_left--; - } - - if (comps_in_scan == 1) - block_y_mcu[comp_list[0]]++; - else - { - for (component_num = 0; component_num < comps_in_scan; component_num++) - { - component_id = comp_list[component_num]; - - block_y_mcu[component_id] += comp_v_samp[component_id]; - } - } - } -} -//------------------------------------------------------------------------------ -// Decode a progressively encoded image. -void jpeg_decoder::init_progressive(void) -{ - int i; - - if (comps_in_frame == 4) - terminate(JPGD_UNSUPPORTED_COLORSPACE); - - // Allocate the coefficient buffers. - for (i = 0; i < comps_in_frame; i++) - { - dc_coeffs[i] = coeff_buf_open(max_mcus_per_row * comp_h_samp[i], - max_mcus_per_col * comp_v_samp[i], 1, 1); - ac_coeffs[i] = coeff_buf_open(max_mcus_per_row * comp_h_samp[i], - max_mcus_per_col * comp_v_samp[i], 8, 8); - } - - for ( ; ; ) - { - int dc_only_scan, refinement_scan; - Pdecode_block_func decode_block_func; - - if (!init_scan()) - break; - - dc_only_scan = (spectral_start == 0); - refinement_scan = (successive_high != 0); - - if ((spectral_start > spectral_end) || (spectral_end > 63)) - terminate(JPGD_BAD_SOS_SPECTRAL); - - if (dc_only_scan) - { - if (spectral_end) - terminate(JPGD_BAD_SOS_SPECTRAL); - } - else if (comps_in_scan != 1) /* AC scans can only contain one component */ - terminate(JPGD_BAD_SOS_SPECTRAL); - - if ((refinement_scan) && (successive_low != successive_high - 1)) - terminate(JPGD_BAD_SOS_SUCCESSIVE); - - if (dc_only_scan) - { - if (refinement_scan) - decode_block_func = progressive_block_decoder::decode_block_dc_refine; - else - decode_block_func = progressive_block_decoder::decode_block_dc_first; - } - else - { - if (refinement_scan) - decode_block_func = progressive_block_decoder::decode_block_ac_refine; - else - decode_block_func = progressive_block_decoder::decode_block_ac_first; - } - - decode_scan(decode_block_func); - - //get_bits_2(bits_left & 7); - - bits_left = 16; - //bit_buf = 0; - get_bits_1(16); - get_bits_1(16); - } - - comps_in_scan = comps_in_frame; - - for (i = 0; i < comps_in_frame; i++) - comp_list[i] = i; - - calc_mcu_block_order(); -} -//------------------------------------------------------------------------------ -void jpeg_decoder::init_sequential(void) -{ - if (!init_scan()) - terminate(JPGD_UNEXPECTED_MARKER); -} -//------------------------------------------------------------------------------ -void jpeg_decoder::decode_start(void) -{ - init_frame(); - - if (progressive_flag) - init_progressive(); - else - init_sequential(); -} -//------------------------------------------------------------------------------ -// Find the start of the JPEG file and reads enough data to determine -// its size, number of components, etc. -void jpeg_decoder::decode_init(Pjpeg_decoder_stream Pstream, bool use_mmx) -{ - init(Pstream, use_mmx); - - locate_sof_marker(); -} -//------------------------------------------------------------------------------ -// Call get_error_code() after constructing to determine if the stream -// was valid or not. You may call the get_width(), get_height(), etc. -// methods after the constructor is called. -// You may then either destruct the object, or begin decoding the image -// by calling begin(), then decode(). -jpeg_decoder::jpeg_decoder(Pjpeg_decoder_stream Pstream, bool use_mmx) -{ - if (setjmp(jmp_state)) - return; - - decode_init(Pstream, use_mmx); -} -//------------------------------------------------------------------------------ -// If you wish to decompress the image, call this method after constructing -// the object. If JPGD_OKAY is returned you may then call decode() to -// fetch the scan lines. -int jpeg_decoder::begin(void) -{ - if (ready_flag) - return (JPGD_OKAY); - - if (error_code) - return (JPGD_FAILED); - - if (setjmp(jmp_state)) - return (JPGD_FAILED); - - decode_start(); - - ready_flag = true; - - return (JPGD_OKAY); -} -//------------------------------------------------------------------------------ -// Completely destroys the decoder object. May be called at any time. -jpeg_decoder::~jpeg_decoder() -{ - free_all_blocks(); -} -//------------------------------------------------------------------------------ - diff --git a/RichgelJpeg/jpegdecoder.h b/RichgelJpeg/jpegdecoder.h deleted file mode 100644 index 18717ca..0000000 --- a/RichgelJpeg/jpegdecoder.h +++ /dev/null @@ -1,713 +0,0 @@ -//------------------------------------------------------------------------------ -// jpegdecoder.h -// Small JPEG Decoder Library v0.93b -// Last updated: Dec. 28, 2001 -// Copyright (C) 1994-2000 Rich Geldreich -// richgel@voicenet.com -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//------------------------------------------------------------------------------ -#ifndef JPEG_DECODER_H -#define JPEG_DECODER_H -//------------------------------------------------------------------------------ -#include -#include -#include -typedef signed char schar; /* 8 bits */ -typedef unsigned char uchar; /* 8 bits */ -typedef signed short int16; /* 16 bits */ -typedef unsigned short uint16; /* 16 bits */ -typedef unsigned short ushort; /* 16 bits */ -typedef unsigned int uint; /* 16/32+ bits */ -typedef unsigned long ulong; /* 32 bits */ -typedef signed int int32; /* 32+ bits */ -#include - -//------------------------------------------------------------------------------ -// Define SUPPORT_X86ASM to include the inline x86 assembler code. -//#define SUPPORT_X86ASM -//------------------------------------------------------------------------------ -// Define SUPPORT_MMX to include MMX support. -//#define SUPPORT_MMX -#undef __int64 -typedef long long __int64; -//------------------------------------------------------------------------------ -#define JPGD_INBUFSIZE 4096 -//------------------------------------------------------------------------------ -// May need to be adjusted if support for other colorspaces/sampling factors is added -#define JPGD_MAXBLOCKSPERMCU 10 -//------------------------------------------------------------------------------ -#define JPGD_MAXHUFFTABLES 8 -#define JPGD_MAXQUANTTABLES 4 -#define JPGD_MAXCOMPONENTS 4 -#define JPGD_MAXCOMPSINSCAN 4 -//------------------------------------------------------------------------------ -// Increase this if you increase the max width! -#define JPGD_MAXBLOCKSPERROW 6144 -//------------------------------------------------------------------------------ -// Max. allocated blocks -#define JPGD_MAXBLOCKS 100 -//------------------------------------------------------------------------------ -#define JPGD_MAX_HEIGHT 8192 -#define JPGD_MAX_WIDTH 8192 -//------------------------------------------------------------------------------ -/* JPEG specific errors */ -#define JPGD_BAD_DHT_COUNTS -200 -#define JPGD_BAD_DHT_INDEX -201 -#define JPGD_BAD_DHT_MARKER -202 -#define JPGD_BAD_DQT_MARKER -203 -#define JPGD_BAD_DQT_TABLE -204 -#define JPGD_BAD_PRECISION -205 -#define JPGD_BAD_HEIGHT -206 -#define JPGD_BAD_WIDTH -207 -#define JPGD_TOO_MANY_COMPONENTS -208 -#define JPGD_BAD_SOF_LENGTH -209 -#define JPGD_BAD_VARIABLE_MARKER -210 -#define JPGD_BAD_DRI_LENGTH -211 -#define JPGD_BAD_SOS_LENGTH -212 -#define JPGD_BAD_SOS_COMP_ID -213 -#define JPGD_W_EXTRA_BYTES_BEFORE_MARKER -214 -#define JPGD_NO_ARITHMITIC_SUPPORT -215 -#define JPGD_UNEXPECTED_MARKER -216 -#define JPGD_NOT_JPEG -217 -#define JPGD_UNSUPPORTED_MARKER -218 -#define JPGD_BAD_DQT_LENGTH -219 -#define JPGD_TOO_MANY_BLOCKS -221 -#define JPGD_UNDEFINED_QUANT_TABLE -222 -#define JPGD_UNDEFINED_HUFF_TABLE -223 -#define JPGD_NOT_SINGLE_SCAN -224 -#define JPGD_UNSUPPORTED_COLORSPACE -225 -#define JPGD_UNSUPPORTED_SAMP_FACTORS -226 -#define JPGD_DECODE_ERROR -227 -#define JPGD_BAD_RESTART_MARKER -228 -#define JPGD_ASSERTION_ERROR -229 -#define JPGD_BAD_SOS_SPECTRAL -230 -#define JPGD_BAD_SOS_SUCCESSIVE -231 -#define JPGD_STREAM_READ -232 -#define JPGD_NOTENOUGHMEM -233 -//------------------------------------------------------------------------------ -#define JPGD_GRAYSCALE 0 -#define JPGD_YH1V1 1 -#define JPGD_YH2V1 2 -#define JPGD_YH1V2 3 -#define JPGD_YH2V2 4 -//------------------------------------------------------------------------------ -const int JPGD_FAILED = -1; -const int JPGD_DONE = 1; -const int JPGD_OKAY = 0; -//------------------------------------------------------------------------------ -typedef enum -{ - M_SOF0 = 0xC0, - M_SOF1 = 0xC1, - M_SOF2 = 0xC2, - M_SOF3 = 0xC3, - - M_SOF5 = 0xC5, - M_SOF6 = 0xC6, - M_SOF7 = 0xC7, - - M_JPG = 0xC8, - M_SOF9 = 0xC9, - M_SOF10 = 0xCA, - M_SOF11 = 0xCB, - - M_SOF13 = 0xCD, - M_SOF14 = 0xCE, - M_SOF15 = 0xCF, - - M_DHT = 0xC4, - - M_DAC = 0xCC, - - M_RST0 = 0xD0, - M_RST1 = 0xD1, - M_RST2 = 0xD2, - M_RST3 = 0xD3, - M_RST4 = 0xD4, - M_RST5 = 0xD5, - M_RST6 = 0xD6, - M_RST7 = 0xD7, - - M_SOI = 0xD8, - M_EOI = 0xD9, - M_SOS = 0xDA, - M_DQT = 0xDB, - M_DNL = 0xDC, - M_DRI = 0xDD, - M_DHP = 0xDE, - M_EXP = 0xDF, - - M_APP0 = 0xE0, - M_APP15 = 0xEF, - - M_JPG0 = 0xF0, - M_JPG13 = 0xFD, - M_COM = 0xFE, - - M_TEM = 0x01, - - M_ERROR = 0x100 -} JPEG_MARKER; -//------------------------------------------------------------------------------ -#define RST0 0xD0 -//------------------------------------------------------------------------------ -typedef struct huff_tables_tag -{ - uint look_up[256]; - uchar code_size[256]; - // FIXME: Is 512 tree entries really enough to handle _all_ possible - // code sets? I think so but not 100% positive. - uint tree[512]; -} huff_tables_t, *Phuff_tables_t; -//------------------------------------------------------------------------------ -typedef struct coeff_buf_tag -{ - uchar *Pdata; - - int block_num_x, block_num_y; - int block_len_x, block_len_y; - - int block_size; - -} coeff_buf_t, *Pcoeff_buf_t; -//------------------------------------------------------------------------------ -class jpeg_decoder; -typedef void (*Pdecode_block_func)(jpeg_decoder *, int, int, int); -//------------------------------------------------------------------------------ -class progressive_block_decoder -{ -public: - static void decode_block_dc_first( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y); - static void decode_block_dc_refine( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y); - static void decode_block_ac_first( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y); - static void decode_block_ac_refine( - jpeg_decoder *Pd, - int component_id, int block_x, int block_y); -}; -//------------------------------------------------------------------------------ -// Input stream interface. -// Derive from this class to fetch input data from sources other than -// files. An important requirement is that you *must* set eof_flag to true -// when no more data is available to fetch! -// The decoder is rather "greedy": it will keep on calling this method until -// its internal input buffer is full, or until the EOF flag is set. -// It the input stream contains data after the JPEG stream's EOI (end of -// image) marker it will probably be pulled into the internal buffer. -// Call the get_total_bytes_read() method to determine the true -// size of the JPEG stream. -class jpeg_decoder_stream -{ -public: - - jpeg_decoder_stream() - { - } - - virtual ~jpeg_decoder_stream() - { - } - - // The read() method is called when the internal input buffer is empty. - // Pbuf - input buffer - // max_bytes_to_read - maximum bytes that can be written to Pbuf - // Peof_flag - set this to true if at end of stream (no more bytes remaining) - // Return -1 on error, otherwise return the number of bytes actually - // written to the buffer (which may be 0). - // Notes: This method will be called in a loop until you set *Peof_flag to - // true or the internal buffer is full. - // The MMX state will be automatically saved/restored before this method is - // called, unlike previous versions. - virtual int read(uchar *Pbuf, int max_bytes_to_read, bool *Peof_flag) = 0; - - virtual void attach(void) - { - } - - virtual void detach(void) - { - } -}; -//------------------------------------------------------------------------------ -typedef jpeg_decoder_stream *Pjpeg_decoder_stream; -//------------------------------------------------------------------------------ -// Here's an example FILE stream class. -class jpeg_decoder_file_stream : public jpeg_decoder_stream -{ - FILE *Pfile; - bool eof_flag, error_flag; - -public: - - jpeg_decoder_file_stream() - { - Pfile = NULL; - eof_flag = false; - error_flag = false; - } - - void close(void) - { - if (Pfile) - { - fclose(Pfile); - Pfile = NULL; - } - - eof_flag = false; - error_flag = false; - } - - virtual ~jpeg_decoder_file_stream() - { - close(); - } - - bool open(const char *Pfilename) - { - close(); - - eof_flag = false; - error_flag = false; - - Pfile = fopen(Pfilename, "rb"); - if (!Pfile) - return (true); - - return (false); - } - - virtual int read(uchar *Pbuf, int max_bytes_to_read, bool *Peof_flag) - { -#if 0 -// Empty/clear MMX state: For testing purposes only! -#ifdef _DEBUG -#ifdef SUPPORT_MMX - _asm - { - pxor mm0, mm0 - pxor mm1, mm1 - pxor mm2, mm2 - pxor mm3, mm3 - pxor mm4, mm4 - pxor mm5, mm5 - pxor mm6, mm6 - pxor mm7, mm7 - emms - } -#endif -#endif -#endif - if (!Pfile) - return (-1); - - if (eof_flag) - { - *Peof_flag = true; - return (0); - } - - if (error_flag) - return (-1); - - int bytes_read = fread(Pbuf, 1, max_bytes_to_read, Pfile); - - if (bytes_read < max_bytes_to_read) - { - if (ferror(Pfile)) - { - error_flag = true; - return (-1); - } - - eof_flag = true; - *Peof_flag = true; - } - - return (bytes_read); - } - - bool get_error_status(void) - { - return (error_flag); - } - - bool reset(void) - { - if (error_flag) - return (true); - - fseek(Pfile, 0, SEEK_SET); - - eof_flag = false; - - return (false); - } - - int get_size(void) - { - if (!Pfile) - return (-1); - - int loc = ftell(Pfile); - - fseek(Pfile, 0, SEEK_END); - - int size = ftell(Pfile); - - fseek(Pfile, loc, SEEK_SET); - - return (size); - } -}; -//------------------------------------------------------------------------------ -typedef jpeg_decoder_file_stream *Pjpeg_decoder_file_stream; -//------------------------------------------------------------------------------ -#define QUANT_TYPE int16 -#define BLOCK_TYPE int16 -//------------------------------------------------------------------------------ -// Disable no return value warning, for rol() method -#pragma warning(push) -#pragma warning( disable : 4035 4799 ) -//------------------------------------------------------------------------------ -class jpeg_decoder -{ - friend class progressive_block_decoder; - -private: - - void free_all_blocks(void); - - void terminate(int status); - - void *alloc(int n); - - void word_clear(void *p, ushort c, uint n); - - void prep_in_buffer(void); - - void read_dht_marker(void); - - void read_dqt_marker(void); - - void read_sof_marker(void); - - void skip_variable_marker(void); - - void read_dri_marker(void); - - void read_sos_marker(void); - - int next_marker(void); - - int process_markers(void); - - void locate_soi_marker(void); - - void locate_sof_marker(void); - - int locate_sos_marker(void); - - void init(Pjpeg_decoder_stream Pstream, bool use_mmx); - - void create_look_ups(void); - - void fix_in_buffer(void); - - void transform_row(void); - - Pcoeff_buf_t coeff_buf_open( - int block_num_x, int block_num_y, - int block_len_x, int block_len_y); - - void coeff_buf_read( - Pcoeff_buf_t cb, - int block_x, int block_y, - BLOCK_TYPE *buffer); - - void coeff_buf_write( - Pcoeff_buf_t cb, - int block_x, int block_y, - BLOCK_TYPE *buffer); - - BLOCK_TYPE *coeff_buf_getp( - Pcoeff_buf_t cb, - int block_x, int block_y); - - void load_next_row(void); - - void decode_next_row(void); -#ifdef SUPPORT_MMX - void decode_next_row_mmx(void); -#endif - - void make_huff_table( - int index, - Phuff_tables_t hs); - - void check_quant_tables(void); - - void check_huff_tables(void); - - void calc_mcu_block_order(void); - - int init_scan(void); - - void init_frame(void); - - void process_restart(void); - - void decode_scan( - Pdecode_block_func decode_block_func); - - void init_progressive(void); - - void init_sequential(void); - - void decode_start(void); - - void decode_init(Pjpeg_decoder_stream Pstream, bool use_mmx); - - void H2V2Convert(void); - void H2V1Convert(void); - void H1V2Convert(void); - void H1V1Convert(void); - void GrayConvert(void); - - void find_eoi(void); -//------------------ - inline uint rol(uint i, uchar j); - inline uint get_char(void); - inline uint get_char(bool *Ppadding_flag); - inline void stuff_char(uchar q); - inline uchar get_octet(void); - inline uint get_bits_1(int num_bits); - inline uint get_bits_2(int numbits); - inline int huff_decode(Phuff_tables_t Ph); -#ifdef SUPPORT_X86ASM - inline uint huff_extend(uint i, int c); -#endif - inline uchar clamp(int i); - -#ifdef SUPPORT_MMX - inline uint get_high_byte_mmx(void); - inline uint get_high_word_mmx(void); - inline void get_bits_2_mmx_init(void); - inline void get_bits_2_mmx_deinit(void); - inline uint get_bits_2_mmx(int numbits); - inline int huff_decode_mmx(Phuff_tables_t Ph); -#endif -//------------------ - int image_x_size; - int image_y_size; - - Pjpeg_decoder_stream Pstream; - - int progressive_flag; - - uchar *huff_num[JPGD_MAXHUFFTABLES]; /* pointer to number of Huffman codes per bit size */ - uchar *huff_val[JPGD_MAXHUFFTABLES]; /* pointer to Huffman codes per bit size */ - - QUANT_TYPE *quant[JPGD_MAXQUANTTABLES]; /* pointer to quantization tables */ - - int scan_type; /* Grey, Yh1v1, Yh1v2, Yh2v1, Yh2v2, - CMYK111, CMYK4114 */ - - int comps_in_frame; /* # of components in frame */ - int comp_h_samp[JPGD_MAXCOMPONENTS]; /* component's horizontal sampling factor */ - int comp_v_samp[JPGD_MAXCOMPONENTS]; /* component's vertical sampling factor */ - int comp_quant[JPGD_MAXCOMPONENTS]; /* component's quantization table selector */ - int comp_ident[JPGD_MAXCOMPONENTS]; /* component's ID */ - - int comp_h_blocks[JPGD_MAXCOMPONENTS]; - int comp_v_blocks[JPGD_MAXCOMPONENTS]; - - int comps_in_scan; /* # of components in scan */ - int comp_list[JPGD_MAXCOMPSINSCAN]; /* components in this scan */ - int comp_dc_tab[JPGD_MAXCOMPONENTS]; /* component's DC Huffman coding table selector */ - int comp_ac_tab[JPGD_MAXCOMPONENTS]; /* component's AC Huffman coding table selector */ - - int spectral_start; /* spectral selection start */ - int spectral_end; /* spectral selection end */ - int successive_low; /* successive approximation low */ - int successive_high; /* successive approximation high */ - - int max_mcu_x_size; /* MCU's max. X size in pixels */ - int max_mcu_y_size; /* MCU's max. Y size in pixels */ - - int blocks_per_mcu; - int max_blocks_per_row; - int mcus_per_row, mcus_per_col; - - int mcu_org[JPGD_MAXBLOCKSPERMCU]; - - int total_lines_left; /* total # lines left in image */ - int mcu_lines_left; /* total # lines left in this MCU */ - - int real_dest_bytes_per_scan_line; - int dest_bytes_per_scan_line; /* rounded up */ - int dest_bytes_per_pixel; /* currently, 4 (RGB) or 1 (Y) */ - - void *blocks[JPGD_MAXBLOCKS]; /* list of all dynamically allocated blocks */ - - Phuff_tables_t h[JPGD_MAXHUFFTABLES]; - - Pcoeff_buf_t dc_coeffs[JPGD_MAXCOMPONENTS]; - Pcoeff_buf_t ac_coeffs[JPGD_MAXCOMPONENTS]; - - int eob_run; - - int block_y_mcu[JPGD_MAXCOMPONENTS]; - - uchar *Pin_buf_ofs; - int in_buf_left; - int tem_flag; - bool eof_flag; - - uchar padd_1[128]; - uchar in_buf[JPGD_INBUFSIZE + 128]; - uchar padd_2[128]; - - int bits_left; - union - { - uint bit_buf; - uint bit_buf_64[2]; - }; - - uint saved_mm1[2]; - - bool use_mmx_getbits; - - int restart_interval; - int restarts_left; - int next_restart_num; - - int max_mcus_per_row; - int max_blocks_per_mcu; - - int max_mcus_per_col; - - uint *component[JPGD_MAXBLOCKSPERMCU]; /* points into the lastdcvals table */ - uint last_dc_val[JPGD_MAXCOMPONENTS]; - - Phuff_tables_t dc_huff_seg[JPGD_MAXBLOCKSPERMCU]; - Phuff_tables_t ac_huff_seg[JPGD_MAXBLOCKSPERMCU]; - - BLOCK_TYPE *block_seg[JPGD_MAXBLOCKSPERROW]; - int block_max_zag_set[JPGD_MAXBLOCKSPERROW]; - - uchar *Psample_buf; - //int block_num[JPGD_MAXBLOCKSPERROW]; - - int crr[256]; - int cbb[256]; - int padd; - long crg[256]; - long cbg[256]; - - uchar *scan_line_0; - uchar *scan_line_1; - - BLOCK_TYPE temp_block[64]; - - bool use_mmx; - bool use_mmx_idct; - bool mmx_active; - - int error_code; - bool ready_flag; - - jmp_buf jmp_state; - - int total_bytes_read; - -public: - - // If SUPPORT_MMX is not defined, the use_mmx flag is ignored. - jpeg_decoder(Pjpeg_decoder_stream Pstream, - bool use_mmx); - - int begin(void); - - int decode(void * *Pscan_line_ofs, uint *Pscan_line_len); - - ~jpeg_decoder(); - - int get_error_code(void) - { - return (error_code); - } - - int get_width(void) - { - return (image_x_size); - } - - int get_height(void) - { - return (image_y_size); - } - - int get_num_components(void) - { - return (comps_in_frame); - } - - int get_bytes_per_pixel(void) - { - return (dest_bytes_per_pixel); - } - - int get_bytes_per_scan_line(void) - { - return (image_x_size * get_bytes_per_pixel()); - } - - int get_total_bytes_read(void) - { - return (total_bytes_read); - } -}; -//------------------------------------------------------------------------------ -#include "jpegdecoder.inl" -//------------------------------------------------------------------------------ -#pragma warning(pop) -//------------------------------------------------------------------------------ -typedef jpeg_decoder *Pjpeg_decoder; -//------------------------------------------------------------------------------ -// idct.cpp -void idct(BLOCK_TYPE *data, uchar *Pdst_ptr); -//------------------------------------------------------------------------------ -// fidctfst.cpp -void jpeg_idct_ifast ( - BLOCK_TYPE* inptr, - short *quantptr, - uchar * *outptr, - int output_col); - -void jpeg_idct_ifast_deinit(void); - -bool jpeg_idct_ifast_avail(void); -//------------------------------------------------------------------------------ -#endif -//------------------------------------------------------------------------------ - diff --git a/RichgelJpeg/jpegdecoder.inl b/RichgelJpeg/jpegdecoder.inl deleted file mode 100644 index 0b10570..0000000 --- a/RichgelJpeg/jpegdecoder.inl +++ /dev/null @@ -1,456 +0,0 @@ -//------------------------------------------------------------------------------ -// inlines-- moved from .h file for clarity -//------------------------------------------------------------------------------ -// Logical rotate left operation. -inline uint jpeg_decoder::rol(uint i, uchar j) -{ -#ifdef SUPPORT_X86ASM - // Breaks the rules a bit.. return value is in eax. - _asm - { - Mov eax, i - Mov cl, j - rol eax, cl - } -#else - return ((i << j) | (i >> (32 - j))); -#endif -} -//------------------------------------------------------------------------------ -// Retrieve one character from the input stream. -inline uint jpeg_decoder::get_char(void) -{ - // Any bytes remaining in buffer? - if (!in_buf_left) - { - // Try to get more bytes. - prep_in_buffer(); - // Still nothing to get? - if (!in_buf_left) - { - // Padd the end of the stream with 0xFF 0xD9 (EOI marker) - // FIXME: Is there a better padding pattern to use? - int t = tem_flag; - tem_flag ^= 1; - if (t) - return (0xD9); - else - return (0xFF); - } - } - - uint c = *Pin_buf_ofs++; - in_buf_left--; - - return (c); -} -//------------------------------------------------------------------------------ -// Same as previus method, except can indicate if the character is -// a "padd" character or not. -inline uint jpeg_decoder::get_char(bool *Ppadding_flag) -{ - if (!in_buf_left) - { - prep_in_buffer(); - if (!in_buf_left) - { - *Ppadding_flag = true; - int t = tem_flag; - tem_flag ^= 1; - if (t) - return (0xD9); - else - return (0xFF); - } - } - - *Ppadding_flag = false; - - uint c = *Pin_buf_ofs++; - in_buf_left--; - - return (c); -} -//------------------------------------------------------------------------------ -// Inserts a previously retrieved character back into the input buffer. -inline void jpeg_decoder::stuff_char(uchar q) -{ - *(--Pin_buf_ofs) = q; - in_buf_left++; -} -//------------------------------------------------------------------------------ -// Retrieves one character from the input stream, but does -// not read past markers. Will continue to return 0xFF when a -// marker is encountered. -// FIXME: Bad name? -inline uchar jpeg_decoder::get_octet(void) -{ - bool padding_flag; - int c = get_char(&padding_flag); - - if (c == 0xFF) - { - if (padding_flag) - return (0xFF); - - c = get_char(&padding_flag); - if (padding_flag) - { - stuff_char(0xFF); - return (0xFF); - } - - if (c == 0x00) - return (0xFF); - else - { - stuff_char(c); - stuff_char(0xFF); - return (0xFF); - } - } - - return (c); -} -//------------------------------------------------------------------------------ -// Retrieves a variable number of bits from the input stream. -// Does not recognize markers. -inline uint jpeg_decoder::get_bits_1(int num_bits) -{ - uint i; - - i = (bit_buf >> (16 - num_bits)) & ((1 << num_bits) - 1); - - if ((bits_left -= num_bits) <= 0) - { - bit_buf = rol(bit_buf, num_bits += bits_left); - - uint c1 = get_char(); - uint c2 = get_char(); - - bit_buf = (bit_buf & 0xFFFF) | (((ulong)c1) << 24) | (((ulong)c2) << 16); - - bit_buf = rol(bit_buf, -bits_left); - - bits_left += 16; - } - else - bit_buf = rol(bit_buf, num_bits); - - return i; -} -//------------------------------------------------------------------------------ -// Retrieves a variable number of bits from the input stream. -// Markers will not be read into the input bit buffer. Instead, -// an infinite number of all 1's will be returned when a marker -// is encountered. -// FIXME: Is it better to return all 0's instead, like the older implementation? -inline uint jpeg_decoder::get_bits_2(int numbits) -{ - uint i; - - i = (bit_buf >> (16 - numbits)) & ((1 << numbits) - 1); - - if ((bits_left -= numbits) <= 0) - { - bit_buf = rol(bit_buf, numbits += bits_left); - - uint c1 = get_octet(); - uint c2 = get_octet(); - - bit_buf = (bit_buf & 0xFFFF) | (((ulong)c1) << 24) | (((ulong)c2) << 16); - - bit_buf = rol(bit_buf, -bits_left); - - bits_left += 16; - } - else - bit_buf = rol(bit_buf, numbits); - - return i; -} -//------------------------------------------------------------------------------ -// Decodes a Huffman encoded symbol. -inline int jpeg_decoder::huff_decode(Phuff_tables_t Ph) -{ - int symbol; - - // Check first 8-bits: do we have a complete symbol? - if ((symbol = Ph->look_up[(bit_buf >> 8) & 0xFF]) < 0) - { - // Decode more bits, use a tree traversal to find symbol. - get_bits_2(8); - - do - { - symbol = Ph->tree[~symbol + (1 - get_bits_2(1))]; - } while (symbol < 0); - } - else - get_bits_2(Ph->code_size[symbol]); - - return symbol; -} -//------------------------------------------------------------------------------ -// Tables and macro used to fully decode the DPCM differences. -// (Note: In x86 asm this can be done without using tables.) -const int extend_test[16] = /* entry n is 2**(n-1) */ - { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, - 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; - -const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ - { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, - ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, - ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, - ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; - -// used by huff_extend() -const int extend_mask[] = -{ - 0, - (1<<0), (1<<1), (1<<2), (1<<3), - (1<<4), (1<<5), (1<<6), (1<<7), - (1<<8), (1<<9), (1<<10), (1<<11), - (1<<12), (1<<13), (1<<14), (1<<15), - (1<<16), -}; - -#define HUFF_EXTEND_TBL(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) - -#ifdef SUPPORT_X86ASM -// Use the inline ASM version instead to prevent jump misprediction issues - #define HUFF_EXTEND(x,s) huff_extend(x, s) - #define HUFF_EXTEND_P(x,s) Pd->huff_extend(x, s) -#else - #define HUFF_EXTEND(x,s) HUFF_EXTEND_TBL(x,s) - #define HUFF_EXTEND_P(x,s) HUFF_EXTEND_TBL(x,s) -#endif -//------------------------------------------------------------------------------ -#ifdef SUPPORT_X86ASM -// This code converts the raw unsigned coefficient bits -// read from the data stream to the proper signed range. -// There are many ways of doing this, see the HUFF_EXTEND_TBL -// macro for an alternative way. -// It purposelly avoids any decision making that requires jumping. -inline uint jpeg_decoder::huff_extend(uint i, int c) -{ - _asm - { - mov ecx, c - mov eax, i - cmp eax, [ecx*4+extend_mask] - sbb edx, edx - shl edx, cl - adc eax, edx - } -} -#endif -//------------------------------------------------------------------------------ -// Clamps a value between 0-255. -inline uchar jpeg_decoder::clamp(int i) -{ - if (i & 0xFFFFFF00) - i = (((~i) >> 31) & 0xFF); - - return (i); -} -//------------------------------------------------------------------------------ -#ifdef SUPPORT_MMX -//------------------------------------------------------------------------------ -inline uint jpeg_decoder::get_high_byte_mmx(void) -{ - _asm - { - movq mm1, mm0 - psrlq mm1, 56 - movd eax, mm1 - } -} -//------------------------------------------------------------------------------ -inline uint jpeg_decoder::get_high_word_mmx(void) -{ - _asm - { - movq mm1, mm0 - psrlq mm1, 48 - movd eax, mm1 - } -} -//------------------------------------------------------------------------------ -inline void jpeg_decoder::get_bits_2_mmx_init(void) -{ - assert(!mmx_active); - mmx_active = true; - - _asm - { - mov esi, this - movq mm0, [esi].bit_buf - movq mm1, [esi].saved_mm1 - } -} -//------------------------------------------------------------------------------ -inline void jpeg_decoder::get_bits_2_mmx_deinit(void) -{ - assert(mmx_active); - mmx_active = false; - - _asm - { - mov esi, this - movq [esi].bit_buf, mm0 - movq [esi].saved_mm1, mm1 - emms - } -} -//------------------------------------------------------------------------------ -static __int64 cmp_mask = 0xFFFFFFFFFFFFFFFF; -static __int64 zero = 0; -//------------------------------------------------------------------------------ -//FIXME: This function doesn't compile right with the Intel Compiler in Release builds. -//Something to do with funciton inlining. -inline uint jpeg_decoder::get_bits_2_mmx(int numbits) -{ - _asm - { - // is the "mov esi, this" really necessary? - // this is safe but it's probably already "this" anyway - mov esi, this - mov ecx, numbits - - mov edx, 64 - movd mm3, ecx - - sub edx, ecx - movq mm1, mm0 - - movd mm2, edx - sub [esi].bits_left, ecx - - psrlq mm1, mm2 - Jg gb2_done -//----------------------------- - add ecx, [esi].bits_left - cmp [esi].in_buf_left, 12 - - movd mm4, ecx - mov edi, [esi].Pin_buf_ofs - - psllq mm0, mm4 - jb gb2_slowload -//----------------------------- -// FIXME: Pair better! - - mov eax, [edi] - mov ebx, [edi+4] - -// FIXME: Is there a better way to do this other than using bswap? - bswap eax - bswap ebx - - movd mm4, eax - movd mm3, ebx - - psllq mm4, 32 - add [esi].Pin_buf_ofs, 6 - - por mm3, mm4 - mov ecx, [esi].bits_left - - psrlq mm3, 16 - neg ecx - - movq mm4, mm3 - sub [esi].in_buf_left, 6 - - pcmpeqb mm4, cmp_mask - por mm0, mm3 - - pcmpeqd mm4, zero - movd mm3, ecx - - pxor mm4, cmp_mask - movd eax, mm1 - - psrlq mm4, 1 - add [esi].bits_left, 48 - - movd ebx, mm4 - psllq mm0, mm3 - - test ebx, ebx - jz gb2_return -//----------------------------- - psrlq mm0, mm3 - sub [esi].bits_left, 48 - sub [esi].Pin_buf_ofs, 6 - add [esi].in_buf_left, 6 - -gb2_slowload: - psrlq mm0, 48 - } - - for (int i = 0; i < 6; i++) - { - uint c = get_octet(); - - _asm - { - movd mm3, c - psllq mm0, 8 - por mm0, mm3 - } - } - - _asm - { - mov esi, this - mov ecx, [esi].bits_left - neg ecx - movd mm3, ecx - add [esi].bits_left, 48 - -gb2_done: - movd eax, mm1 - psllq mm0, mm3 - } -gb2_return:; -} -//------------------------------------------------------------------------------ -inline int jpeg_decoder::huff_decode_mmx(Phuff_tables_t Ph) -{ - int symbol; - //uint d = get_high_word_mmx(); - uint d; - _asm - { - movq mm1, mm0 - psrlq mm1, 48 - movd eax, mm1 - mov d, eax - } - - // Check first 8-bits: do we have a complete symbol? - if ((symbol = Ph->look_up[(d >> 8) & 0xFF]) < 0) - { - uint ofs = 7; - d = ~d; // invert d here so we don't have to do it inside the loop - - do - { - symbol = Ph->tree[~symbol + ((d >> ofs) & 1)]; - ofs--; - } while (symbol < 0); - - // Decode more bits, use a tree traversal to find symbol. - get_bits_2_mmx(8 + (7 - ofs)); - } - else - get_bits_2_mmx(Ph->code_size[symbol]); - - return symbol; -} -//------------------------------------------------------------------------------ -#endif -//------------------------------------------------------------------------------ - diff --git a/RichgelJpeg/jpgd.cpp b/RichgelJpeg/jpgd.cpp new file mode 100644 index 0000000..194535e --- /dev/null +++ b/RichgelJpeg/jpgd.cpp @@ -0,0 +1,3283 @@ +// jpgd.cpp - C++ class for JPEG decompression. Written by Richard Geldreich between 1994-2020. +// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2. +// Supports box and linear chroma upsampling. +// +// Released under two licenses. You are free to choose which license you want: +// License 1: +// Public Domain +// +// License 2: +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Alex Evans: Linear memory allocator (taken from jpge.h). +// v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings +// v2.00, March 20, 2020: Fuzzed with zzuf and afl. Fixed several issues, converted most assert()'s to run-time checks. Added chroma upsampling. Removed freq. domain upsampling. gcc/clang warnings. +// +// Important: +// #define JPGD_USE_SSE2 to 0 to completely disable SSE2 usage. +// +#include "jpgd.h" +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +#ifndef JPGD_USE_SSE2 + + #if defined(__GNUC__) + #if defined(__SSE2__) + #define JPGD_USE_SSE2 (1) + #endif + #elif defined(_MSC_VER) + #if defined(_M_X64) + #define JPGD_USE_SSE2 (1) + #endif + #endif + +#endif + +#define JPGD_TRUE (1) +#define JPGD_FALSE (0) + +#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b)) +#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b)) + +namespace jpgd { + + static inline void* jpgd_malloc(size_t nSize) { return malloc(nSize); } + static inline void jpgd_free(void* p) { free(p); } + + // DCT coefficients are stored in this sequence. + static int g_ZAG[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; + + enum JPEG_MARKER + { + M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8, + M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC, + M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7, + M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF, + M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0 + }; + + enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 }; + +#if JPGD_USE_SSE2 +#include "jpgd_idct.h" +#endif + +#define CONST_BITS 13 +#define PASS1_BITS 2 +#define SCALEDONE ((int32)1) + +#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */ + +#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n)) +#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n)) + +#define MULTIPLY(var, cnst) ((var) * (cnst)) + +#define CLAMP(i) ((static_cast(i) > 255) ? (((~i) >> 31) & 0xFF) : (i)) + + static inline int left_shifti(int val, uint32_t bits) + { + return static_cast(static_cast(val) << bits); + } + + // Compiler creates a fast path 1D IDCT for X non-zero columns + template + struct Row + { + static void idct(int* pTemp, const jpgd_block_coeff_t* pSrc) + { + // ACCESS_COL() will be optimized at compile time to either an array access, or 0. Good compilers will then optimize out muls against 0. +#define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0) + + const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6); + + const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + const int tmp2 = z1 + MULTIPLY(z3, -FIX_1_847759065); + const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + const int tmp0 = left_shifti(ACCESS_COL(0) + ACCESS_COL(4), CONST_BITS); + const int tmp1 = left_shifti(ACCESS_COL(0) - ACCESS_COL(4), CONST_BITS); + + const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; + + const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1); + + const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3; + const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602); + + const int az1 = MULTIPLY(bz1, -FIX_0_899976223); + const int az2 = MULTIPLY(bz2, -FIX_2_562915447); + const int az3 = MULTIPLY(bz3, -FIX_1_961570560) + bz5; + const int az4 = MULTIPLY(bz4, -FIX_0_390180644) + bz5; + + const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3; + const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4; + const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3; + const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4; + + pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS - PASS1_BITS); + pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS - PASS1_BITS); + pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS - PASS1_BITS); + pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS - PASS1_BITS); + pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS - PASS1_BITS); + pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS - PASS1_BITS); + pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS - PASS1_BITS); + pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS - PASS1_BITS); + } + }; + + template <> + struct Row<0> + { + static void idct(int* pTemp, const jpgd_block_coeff_t* pSrc) + { + (void)pTemp; + (void)pSrc; + } + }; + + template <> + struct Row<1> + { + static void idct(int* pTemp, const jpgd_block_coeff_t* pSrc) + { + const int dcval = left_shifti(pSrc[0], PASS1_BITS); + + pTemp[0] = dcval; + pTemp[1] = dcval; + pTemp[2] = dcval; + pTemp[3] = dcval; + pTemp[4] = dcval; + pTemp[5] = dcval; + pTemp[6] = dcval; + pTemp[7] = dcval; + } + }; + + // Compiler creates a fast path 1D IDCT for X non-zero rows + template + struct Col + { + static void idct(uint8* pDst_ptr, const int* pTemp) + { + // ACCESS_ROW() will be optimized at compile time to either an array access, or 0. +#define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0) + + const int z2 = ACCESS_ROW(2); + const int z3 = ACCESS_ROW(6); + + const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + const int tmp2 = z1 + MULTIPLY(z3, -FIX_1_847759065); + const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + const int tmp0 = left_shifti(ACCESS_ROW(0) + ACCESS_ROW(4), CONST_BITS); + const int tmp1 = left_shifti(ACCESS_ROW(0) - ACCESS_ROW(4), CONST_BITS); + + const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; + + const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1); + + const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3; + const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602); + + const int az1 = MULTIPLY(bz1, -FIX_0_899976223); + const int az2 = MULTIPLY(bz2, -FIX_2_562915447); + const int az3 = MULTIPLY(bz3, -FIX_1_961570560) + bz5; + const int az4 = MULTIPLY(bz4, -FIX_0_390180644) + bz5; + + const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3; + const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4; + const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3; + const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4; + + int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 0] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 7] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 1] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 6] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 2] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 5] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 3] = (uint8)CLAMP(i); + + i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS + PASS1_BITS + 3); + pDst_ptr[8 * 4] = (uint8)CLAMP(i); + } + }; + + template <> + struct Col<1> + { + static void idct(uint8* pDst_ptr, const int* pTemp) + { + int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS + 3); + const uint8 dcval_clamped = (uint8)CLAMP(dcval); + pDst_ptr[0 * 8] = dcval_clamped; + pDst_ptr[1 * 8] = dcval_clamped; + pDst_ptr[2 * 8] = dcval_clamped; + pDst_ptr[3 * 8] = dcval_clamped; + pDst_ptr[4 * 8] = dcval_clamped; + pDst_ptr[5 * 8] = dcval_clamped; + pDst_ptr[6 * 8] = dcval_clamped; + pDst_ptr[7 * 8] = dcval_clamped; + } + }; + + static const uint8 s_idct_row_table[] = + { + 1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0, + 4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0, + 6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0, + 6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0, + 8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2, + 8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2, + 8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4, + 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8, + }; + + static const uint8 s_idct_col_table[] = + { + 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 + }; + + // Scalar "fast pathing" IDCT. + static void idct(const jpgd_block_coeff_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag, bool use_simd) + { + (void)use_simd; + + assert(block_max_zag >= 1); + assert(block_max_zag <= 64); + + if (block_max_zag <= 1) + { + int k = ((pSrc_ptr[0] + 4) >> 3) + 128; + k = CLAMP(k); + k = k | (k << 8); + k = k | (k << 16); + + for (int i = 8; i > 0; i--) + { + *(int*)&pDst_ptr[0] = k; + *(int*)&pDst_ptr[4] = k; + pDst_ptr += 8; + } + return; + } + +#if JPGD_USE_SSE2 + if (use_simd) + { + assert((((uintptr_t)pSrc_ptr) & 15) == 0); + assert((((uintptr_t)pDst_ptr) & 15) == 0); + idctSSEShortU8(pSrc_ptr, pDst_ptr); + return; + } +#endif + + int temp[64]; + + const jpgd_block_coeff_t* pSrc = pSrc_ptr; + int* pTemp = temp; + + const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8]; + int i; + for (i = 8; i > 0; i--, pRow_tab++) + { + switch (*pRow_tab) + { + case 0: Row<0>::idct(pTemp, pSrc); break; + case 1: Row<1>::idct(pTemp, pSrc); break; + case 2: Row<2>::idct(pTemp, pSrc); break; + case 3: Row<3>::idct(pTemp, pSrc); break; + case 4: Row<4>::idct(pTemp, pSrc); break; + case 5: Row<5>::idct(pTemp, pSrc); break; + case 6: Row<6>::idct(pTemp, pSrc); break; + case 7: Row<7>::idct(pTemp, pSrc); break; + case 8: Row<8>::idct(pTemp, pSrc); break; + } + + pSrc += 8; + pTemp += 8; + } + + pTemp = temp; + + const int nonzero_rows = s_idct_col_table[block_max_zag - 1]; + for (i = 8; i > 0; i--) + { + switch (nonzero_rows) + { + case 1: Col<1>::idct(pDst_ptr, pTemp); break; + case 2: Col<2>::idct(pDst_ptr, pTemp); break; + case 3: Col<3>::idct(pDst_ptr, pTemp); break; + case 4: Col<4>::idct(pDst_ptr, pTemp); break; + case 5: Col<5>::idct(pDst_ptr, pTemp); break; + case 6: Col<6>::idct(pDst_ptr, pTemp); break; + case 7: Col<7>::idct(pDst_ptr, pTemp); break; + case 8: Col<8>::idct(pDst_ptr, pTemp); break; + } + + pTemp++; + pDst_ptr++; + } + } + + // Retrieve one character from the input stream. + inline uint jpeg_decoder::get_char() + { + // Any bytes remaining in buffer? + if (!m_in_buf_left) + { + // Try to get more bytes. + prep_in_buffer(); + // Still nothing to get? + if (!m_in_buf_left) + { + // Pad the end of the stream with 0xFF 0xD9 (EOI marker) + int t = m_tem_flag; + m_tem_flag ^= 1; + if (t) + return 0xD9; + else + return 0xFF; + } + } + + uint c = *m_pIn_buf_ofs++; + m_in_buf_left--; + + return c; + } + + // Same as previous method, except can indicate if the character is a pad character or not. + inline uint jpeg_decoder::get_char(bool* pPadding_flag) + { + if (!m_in_buf_left) + { + prep_in_buffer(); + if (!m_in_buf_left) + { + *pPadding_flag = true; + int t = m_tem_flag; + m_tem_flag ^= 1; + if (t) + return 0xD9; + else + return 0xFF; + } + } + + *pPadding_flag = false; + + uint c = *m_pIn_buf_ofs++; + m_in_buf_left--; + + return c; + } + + // Inserts a previously retrieved character back into the input buffer. + inline void jpeg_decoder::stuff_char(uint8 q) + { + // This could write before the input buffer, but we've placed another array there. + *(--m_pIn_buf_ofs) = q; + m_in_buf_left++; + } + + // Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered. + inline uint8 jpeg_decoder::get_octet() + { + bool padding_flag; + int c = get_char(&padding_flag); + + if (c == 0xFF) + { + if (padding_flag) + return 0xFF; + + c = get_char(&padding_flag); + if (padding_flag) + { + stuff_char(0xFF); + return 0xFF; + } + + if (c == 0x00) + return 0xFF; + else + { + stuff_char(static_cast(c)); + stuff_char(0xFF); + return 0xFF; + } + } + + return static_cast(c); + } + + // Retrieves a variable number of bits from the input stream. Does not recognize markers. + inline uint jpeg_decoder::get_bits(int num_bits) + { + if (!num_bits) + return 0; + + uint i = m_bit_buf >> (32 - num_bits); + + if ((m_bits_left -= num_bits) <= 0) + { + m_bit_buf <<= (num_bits += m_bits_left); + + uint c1 = get_char(); + uint c2 = get_char(); + m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2; + + m_bit_buf <<= -m_bits_left; + + m_bits_left += 16; + + assert(m_bits_left >= 0); + } + else + m_bit_buf <<= num_bits; + + return i; + } + + // Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered. + inline uint jpeg_decoder::get_bits_no_markers(int num_bits) + { + if (!num_bits) + return 0; + + assert(num_bits <= 16); + + uint i = m_bit_buf >> (32 - num_bits); + + if ((m_bits_left -= num_bits) <= 0) + { + m_bit_buf <<= (num_bits += m_bits_left); + + if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF)) + { + uint c1 = get_octet(); + uint c2 = get_octet(); + m_bit_buf |= (c1 << 8) | c2; + } + else + { + m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1]; + m_in_buf_left -= 2; + m_pIn_buf_ofs += 2; + } + + m_bit_buf <<= -m_bits_left; + + m_bits_left += 16; + + assert(m_bits_left >= 0); + } + else + m_bit_buf <<= num_bits; + + return i; + } + + // Decodes a Huffman encoded symbol. + inline int jpeg_decoder::huff_decode(huff_tables* pH) + { + if (!pH) + stop_decoding(JPGD_DECODE_ERROR); + + int symbol; + // Check first 8-bits: do we have a complete symbol? + if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0) + { + // Decode more bits, use a tree traversal to find symbol. + int ofs = 23; + do + { + unsigned int idx = -(int)(symbol + ((m_bit_buf >> ofs) & 1)); + + // This should never happen, but to be safe I'm turning these asserts into a run-time check. + if ((idx >= JPGD_HUFF_TREE_MAX_LENGTH) || (ofs < 0)) + stop_decoding(JPGD_DECODE_ERROR); + + symbol = pH->tree[idx]; + ofs--; + } while (symbol < 0); + + get_bits_no_markers(8 + (23 - ofs)); + } + else + { + assert(symbol < JPGD_HUFF_CODE_SIZE_MAX_LENGTH); + get_bits_no_markers(pH->code_size[symbol]); + } + + return symbol; + } + + // Decodes a Huffman encoded symbol. + inline int jpeg_decoder::huff_decode(huff_tables* pH, int& extra_bits) + { + int symbol; + + if (!pH) + stop_decoding(JPGD_DECODE_ERROR); + + // Check first 8-bits: do we have a complete symbol? + if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0) + { + // Use a tree traversal to find symbol. + int ofs = 23; + do + { + unsigned int idx = -(int)(symbol + ((m_bit_buf >> ofs) & 1)); + + // This should never happen, but to be safe I'm turning these asserts into a run-time check. + if ((idx >= JPGD_HUFF_TREE_MAX_LENGTH) || (ofs < 0)) + stop_decoding(JPGD_DECODE_ERROR); + + symbol = pH->tree[idx]; + ofs--; + } while (symbol < 0); + + get_bits_no_markers(8 + (23 - ofs)); + + extra_bits = get_bits_no_markers(symbol & 0xF); + } + else + { + if (symbol & 0x8000) + { + //get_bits_no_markers((symbol >> 8) & 31); + assert(((symbol >> 8) & 31) <= 15); + get_bits_no_markers((symbol >> 8) & 15); + extra_bits = symbol >> 16; + } + else + { + int code_size = (symbol >> 8) & 31; + int num_extra_bits = symbol & 0xF; + int bits = code_size + num_extra_bits; + + if (bits <= 16) + extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1); + else + { + get_bits_no_markers(code_size); + extra_bits = get_bits_no_markers(num_extra_bits); + } + } + + symbol &= 0xFF; + } + + return symbol; + } + + // Tables and macro used to fully decode the DPCM differences. + static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + static const int s_extend_offset[16] = { 0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, -4095, -8191, -16383, -32767 }; + //static const int s_extend_mask[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15), (1 << 16) }; + +#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x)) + + // Unconditionally frees all allocated m_blocks. + void jpeg_decoder::free_all_blocks() + { + m_pStream = NULL; + for (mem_block* b = m_pMem_blocks; b; ) + { + mem_block* n = b->m_pNext; + jpgd_free(b); + b = n; + } + m_pMem_blocks = NULL; + } + + // This method handles all errors. It will never return. + // It could easily be changed to use C++ exceptions. + JPGD_NORETURN void jpeg_decoder::stop_decoding(jpgd_status status) + { + m_error_code = status; + free_all_blocks(); + longjmp(m_jmp_state, status); + } + + void* jpeg_decoder::alloc(size_t nSize, bool zero) + { + nSize = (JPGD_MAX(nSize, 1) + 3) & ~3; + char* rv = NULL; + for (mem_block* b = m_pMem_blocks; b; b = b->m_pNext) + { + if ((b->m_used_count + nSize) <= b->m_size) + { + rv = b->m_data + b->m_used_count; + b->m_used_count += nSize; + break; + } + } + if (!rv) + { + int capacity = JPGD_MAX(32768 - 256, (nSize + 2047) & ~2047); + mem_block* b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity); + if (!b) + { + stop_decoding(JPGD_NOTENOUGHMEM); + } + + b->m_pNext = m_pMem_blocks; + m_pMem_blocks = b; + b->m_used_count = nSize; + b->m_size = capacity; + rv = b->m_data; + } + if (zero) memset(rv, 0, nSize); + return rv; + } + + void* jpeg_decoder::alloc_aligned(size_t nSize, uint32_t align, bool zero) + { + assert((align >= 1U) && ((align & (align - 1U)) == 0U)); + void *p = alloc(nSize + align - 1U, zero); + p = (void *)( ((uintptr_t)p + (align - 1U)) & ~((uintptr_t)(align - 1U)) ); + return p; + } + + void jpeg_decoder::word_clear(void* p, uint16 c, uint n) + { + uint8* pD = (uint8*)p; + const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF; + while (n) + { + pD[0] = l; + pD[1] = h; + pD += 2; + n--; + } + } + + // Refill the input buffer. + // This method will sit in a loop until (A) the buffer is full or (B) + // the stream's read() method reports and end of file condition. + void jpeg_decoder::prep_in_buffer() + { + m_in_buf_left = 0; + m_pIn_buf_ofs = m_in_buf; + + if (m_eof_flag) + return; + + do + { + int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag); + if (bytes_read == -1) + stop_decoding(JPGD_STREAM_READ); + + m_in_buf_left += bytes_read; + } while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag)); + + m_total_bytes_read += m_in_buf_left; + + // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid). + // (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.) + word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64); + } + + // Read a Huffman code table. + void jpeg_decoder::read_dht_marker() + { + int i, index, count; + uint8 huff_num[17]; + uint8 huff_val[256]; + + uint num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_DHT_MARKER); + + num_left -= 2; + + while (num_left) + { + index = get_bits(8); + + huff_num[0] = 0; + + count = 0; + + for (i = 1; i <= 16; i++) + { + huff_num[i] = static_cast(get_bits(8)); + count += huff_num[i]; + } + + if (count > 255) + stop_decoding(JPGD_BAD_DHT_COUNTS); + + bool symbol_present[256]; + memset(symbol_present, 0, sizeof(symbol_present)); + + for (i = 0; i < count; i++) + { + const int s = get_bits(8); + + // Check for obviously bogus tables. + if (symbol_present[s]) + stop_decoding(JPGD_BAD_DHT_COUNTS); + + huff_val[i] = static_cast(s); + symbol_present[s] = true; + } + + i = 1 + 16 + count; + + if (num_left < (uint)i) + stop_decoding(JPGD_BAD_DHT_MARKER); + + num_left -= i; + + if ((index & 0x10) > 0x10) + stop_decoding(JPGD_BAD_DHT_INDEX); + + index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1); + + if (index >= JPGD_MAX_HUFF_TABLES) + stop_decoding(JPGD_BAD_DHT_INDEX); + + if (!m_huff_num[index]) + m_huff_num[index] = (uint8*)alloc(17); + + if (!m_huff_val[index]) + m_huff_val[index] = (uint8*)alloc(256); + + m_huff_ac[index] = (index & 0x10) != 0; + memcpy(m_huff_num[index], huff_num, 17); + memcpy(m_huff_val[index], huff_val, 256); + } + } + + // Read a quantization table. + void jpeg_decoder::read_dqt_marker() + { + int n, i, prec; + uint num_left; + uint temp; + + num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_DQT_MARKER); + + num_left -= 2; + + while (num_left) + { + n = get_bits(8); + prec = n >> 4; + n &= 0x0F; + + if (n >= JPGD_MAX_QUANT_TABLES) + stop_decoding(JPGD_BAD_DQT_TABLE); + + if (!m_quant[n]) + m_quant[n] = (jpgd_quant_t*)alloc(64 * sizeof(jpgd_quant_t)); + + // read quantization entries, in zag order + for (i = 0; i < 64; i++) + { + temp = get_bits(8); + + if (prec) + temp = (temp << 8) + get_bits(8); + + m_quant[n][i] = static_cast(temp); + } + + i = 64 + 1; + + if (prec) + i += 64; + + if (num_left < (uint)i) + stop_decoding(JPGD_BAD_DQT_LENGTH); + + num_left -= i; + } + } + + // Read the start of frame (SOF) marker. + void jpeg_decoder::read_sof_marker() + { + int i; + uint num_left; + + num_left = get_bits(16); + + /* precision: sorry, only 8-bit precision is supported */ + if (get_bits(8) != 8) + stop_decoding(JPGD_BAD_PRECISION); + + m_image_y_size = get_bits(16); + + if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT)) + stop_decoding(JPGD_BAD_HEIGHT); + + m_image_x_size = get_bits(16); + + if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH)) + stop_decoding(JPGD_BAD_WIDTH); + + m_comps_in_frame = get_bits(8); + + if (m_comps_in_frame > JPGD_MAX_COMPONENTS) + stop_decoding(JPGD_TOO_MANY_COMPONENTS); + + if (num_left != (uint)(m_comps_in_frame * 3 + 8)) + stop_decoding(JPGD_BAD_SOF_LENGTH); + + for (i = 0; i < m_comps_in_frame; i++) + { + m_comp_ident[i] = get_bits(8); + m_comp_h_samp[i] = get_bits(4); + m_comp_v_samp[i] = get_bits(4); + + if (!m_comp_h_samp[i] || !m_comp_v_samp[i] || (m_comp_h_samp[i] > 2) || (m_comp_v_samp[i] > 2)) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + m_comp_quant[i] = get_bits(8); + if (m_comp_quant[i] >= JPGD_MAX_QUANT_TABLES) + stop_decoding(JPGD_DECODE_ERROR); + } + } + + // Used to skip unrecognized markers. + void jpeg_decoder::skip_variable_marker() + { + uint num_left; + + num_left = get_bits(16); + + if (num_left < 2) + stop_decoding(JPGD_BAD_VARIABLE_MARKER); + + num_left -= 2; + + while (num_left) + { + get_bits(8); + num_left--; + } + } + + // Read a define restart interval (DRI) marker. + void jpeg_decoder::read_dri_marker() + { + if (get_bits(16) != 4) + stop_decoding(JPGD_BAD_DRI_LENGTH); + + m_restart_interval = get_bits(16); + } + + // Read a start of scan (SOS) marker. + void jpeg_decoder::read_sos_marker() + { + uint num_left; + int i, ci, n, c, cc; + + num_left = get_bits(16); + + n = get_bits(8); + + m_comps_in_scan = n; + + num_left -= 3; + + if ((num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN)) + stop_decoding(JPGD_BAD_SOS_LENGTH); + + for (i = 0; i < n; i++) + { + cc = get_bits(8); + c = get_bits(8); + num_left -= 2; + + for (ci = 0; ci < m_comps_in_frame; ci++) + if (cc == m_comp_ident[ci]) + break; + + if (ci >= m_comps_in_frame) + stop_decoding(JPGD_BAD_SOS_COMP_ID); + + if (ci >= JPGD_MAX_COMPONENTS) + stop_decoding(JPGD_DECODE_ERROR); + + m_comp_list[i] = ci; + + m_comp_dc_tab[ci] = (c >> 4) & 15; + m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1); + + if (m_comp_dc_tab[ci] >= JPGD_MAX_HUFF_TABLES) + stop_decoding(JPGD_DECODE_ERROR); + + if (m_comp_ac_tab[ci] >= JPGD_MAX_HUFF_TABLES) + stop_decoding(JPGD_DECODE_ERROR); + } + + m_spectral_start = get_bits(8); + m_spectral_end = get_bits(8); + m_successive_high = get_bits(4); + m_successive_low = get_bits(4); + + if (!m_progressive_flag) + { + m_spectral_start = 0; + m_spectral_end = 63; + } + + num_left -= 3; + + /* read past whatever is num_left */ + while (num_left) + { + get_bits(8); + num_left--; + } + } + + // Finds the next marker. + int jpeg_decoder::next_marker() + { + uint c, bytes; + + bytes = 0; + + do + { + do + { + bytes++; + c = get_bits(8); + } while (c != 0xFF); + + do + { + c = get_bits(8); + } while (c == 0xFF); + + } while (c == 0); + + // If bytes > 0 here, there where extra bytes before the marker (not good). + + return c; + } + + // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is + // encountered. + int jpeg_decoder::process_markers() + { + int c; + + for (; ; ) + { + c = next_marker(); + + switch (c) + { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + // case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + { + return c; + } + case M_DHT: + { + read_dht_marker(); + break; + } + // No arithmitic support - dumb patents! + case M_DAC: + { + stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT); + break; + } + case M_DQT: + { + read_dqt_marker(); + break; + } + case M_DRI: + { + read_dri_marker(); + break; + } + //case M_APP0: /* no need to read the JFIF marker */ + case M_JPG: + case M_RST0: /* no parameters */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + { + stop_decoding(JPGD_UNEXPECTED_MARKER); + break; + } + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ + { + skip_variable_marker(); + break; + } + } + } + } + + // Finds the start of image (SOI) marker. + void jpeg_decoder::locate_soi_marker() + { + uint lastchar, thischar; + uint bytesleft; + + lastchar = get_bits(8); + + thischar = get_bits(8); + + /* ok if it's a normal JPEG file without a special header */ + + if ((lastchar == 0xFF) && (thischar == M_SOI)) + return; + + bytesleft = 4096; + + for (; ; ) + { + if (--bytesleft == 0) + stop_decoding(JPGD_NOT_JPEG); + + lastchar = thischar; + + thischar = get_bits(8); + + if (lastchar == 0xFF) + { + if (thischar == M_SOI) + break; + else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end + stop_decoding(JPGD_NOT_JPEG); + } + } + + // Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad. + thischar = (m_bit_buf >> 24) & 0xFF; + + if (thischar != 0xFF) + stop_decoding(JPGD_NOT_JPEG); + } + + // Find a start of frame (SOF) marker. + void jpeg_decoder::locate_sof_marker() + { + locate_soi_marker(); + + int c = process_markers(); + + switch (c) + { + case M_SOF2: + { + m_progressive_flag = JPGD_TRUE; + read_sof_marker(); + break; + } + case M_SOF0: /* baseline DCT */ + case M_SOF1: /* extended sequential DCT */ + { + read_sof_marker(); + break; + } + case M_SOF9: /* Arithmitic coding */ + { + stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT); + break; + } + default: + { + stop_decoding(JPGD_UNSUPPORTED_MARKER); + break; + } + } + } + + // Find a start of scan (SOS) marker. + int jpeg_decoder::locate_sos_marker() + { + int c; + + c = process_markers(); + + if (c == M_EOI) + return JPGD_FALSE; + else if (c != M_SOS) + stop_decoding(JPGD_UNEXPECTED_MARKER); + + read_sos_marker(); + + return JPGD_TRUE; + } + + // Reset everything to default/uninitialized state. + void jpeg_decoder::init(jpeg_decoder_stream* pStream, uint32_t flags) + { + m_flags = flags; + m_pMem_blocks = NULL; + m_error_code = JPGD_SUCCESS; + m_ready_flag = false; + m_image_x_size = m_image_y_size = 0; + m_pStream = pStream; + m_progressive_flag = JPGD_FALSE; + + memset(m_huff_ac, 0, sizeof(m_huff_ac)); + memset(m_huff_num, 0, sizeof(m_huff_num)); + memset(m_huff_val, 0, sizeof(m_huff_val)); + memset(m_quant, 0, sizeof(m_quant)); + + m_scan_type = 0; + m_comps_in_frame = 0; + + memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp)); + memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp)); + memset(m_comp_quant, 0, sizeof(m_comp_quant)); + memset(m_comp_ident, 0, sizeof(m_comp_ident)); + memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks)); + memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks)); + + m_comps_in_scan = 0; + memset(m_comp_list, 0, sizeof(m_comp_list)); + memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab)); + memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab)); + + m_spectral_start = 0; + m_spectral_end = 0; + m_successive_low = 0; + m_successive_high = 0; + m_max_mcu_x_size = 0; + m_max_mcu_y_size = 0; + m_blocks_per_mcu = 0; + m_max_blocks_per_row = 0; + m_mcus_per_row = 0; + m_mcus_per_col = 0; + + memset(m_mcu_org, 0, sizeof(m_mcu_org)); + + m_total_lines_left = 0; + m_mcu_lines_left = 0; + m_num_buffered_scanlines = 0; + m_real_dest_bytes_per_scan_line = 0; + m_dest_bytes_per_scan_line = 0; + m_dest_bytes_per_pixel = 0; + + memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs)); + + memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs)); + memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs)); + memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu)); + + m_eob_run = 0; + + m_pIn_buf_ofs = m_in_buf; + m_in_buf_left = 0; + m_eof_flag = false; + m_tem_flag = 0; + + memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start)); + memset(m_in_buf, 0, sizeof(m_in_buf)); + memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end)); + + m_restart_interval = 0; + m_restarts_left = 0; + m_next_restart_num = 0; + + m_max_mcus_per_row = 0; + m_max_blocks_per_mcu = 0; + m_max_mcus_per_col = 0; + + memset(m_last_dc_val, 0, sizeof(m_last_dc_val)); + m_pMCU_coefficients = NULL; + m_pSample_buf = NULL; + m_pSample_buf_prev = NULL; + m_sample_buf_prev_valid = false; + + m_total_bytes_read = 0; + + m_pScan_line_0 = NULL; + m_pScan_line_1 = NULL; + + // Ready the input buffer. + prep_in_buffer(); + + // Prime the bit buffer. + m_bits_left = 16; + m_bit_buf = 0; + + get_bits(16); + get_bits(16); + + for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++) + m_mcu_block_max_zag[i] = 64; + + m_has_sse2 = false; + +#if JPGD_USE_SSE2 +#ifdef _MSC_VER + int cpu_info[4]; + __cpuid(cpu_info, 1); + const int cpu_info3 = cpu_info[3]; + m_has_sse2 = ((cpu_info3 >> 26U) & 1U) != 0U; +#else + m_has_sse2 = true; +#endif +#endif + } + +#define SCALEBITS 16 +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) +#define FIX(x) ((int) ((x) * (1L<> SCALEBITS; + m_cbb[i] = (FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS; + m_crg[i] = (-FIX(0.71414f)) * k; + m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF; + } + } + + // This method throws back into the stream any bytes that where read + // into the bit buffer during initial marker scanning. + void jpeg_decoder::fix_in_buffer() + { + // In case any 0xFF's where pulled into the buffer during marker scanning. + assert((m_bits_left & 7) == 0); + + if (m_bits_left == 16) + stuff_char((uint8)(m_bit_buf & 0xFF)); + + if (m_bits_left >= 8) + stuff_char((uint8)((m_bit_buf >> 8) & 0xFF)); + + stuff_char((uint8)((m_bit_buf >> 16) & 0xFF)); + stuff_char((uint8)((m_bit_buf >> 24) & 0xFF)); + + m_bits_left = 16; + get_bits_no_markers(16); + get_bits_no_markers(16); + } + + void jpeg_decoder::transform_mcu(int mcu_row) + { + jpgd_block_coeff_t* pSrc_ptr = m_pMCU_coefficients; + if (mcu_row * m_blocks_per_mcu >= m_max_blocks_per_row) + stop_decoding(JPGD_DECODE_ERROR); + + uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64; + + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block], ((m_flags & cFlagDisableSIMD) == 0) && m_has_sse2); + pSrc_ptr += 64; + pDst_ptr += 64; + } + } + + // Loads and dequantizes the next row of (already decoded) coefficients. + // Progressive images only. + void jpeg_decoder::load_next_row() + { + int i; + jpgd_block_coeff_t* p; + jpgd_quant_t* q; + int mcu_row, mcu_block, row_block = 0; + int component_num, component_id; + int block_x_mcu[JPGD_MAX_COMPONENTS]; + + memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int)); + + for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; + + for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + component_id = m_mcu_org[mcu_block]; + if (m_comp_quant[component_id] >= JPGD_MAX_QUANT_TABLES) + stop_decoding(JPGD_DECODE_ERROR); + + q = m_quant[m_comp_quant[component_id]]; + + p = m_pMCU_coefficients + 64 * mcu_block; + + jpgd_block_coeff_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + jpgd_block_coeff_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs); + p[0] = pDC[0]; + memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_coeff_t)); + + for (i = 63; i > 0; i--) + if (p[g_ZAG[i]]) + break; + + m_mcu_block_max_zag[mcu_block] = i + 1; + + for (; i >= 0; i--) + if (p[g_ZAG[i]]) + p[g_ZAG[i]] = static_cast(p[g_ZAG[i]] * q[i]); + + row_block++; + + if (m_comps_in_scan == 1) + block_x_mcu[component_id]++; + else + { + if (++block_x_mcu_ofs == m_comp_h_samp[component_id]) + { + block_x_mcu_ofs = 0; + + if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) + { + block_y_mcu_ofs = 0; + + block_x_mcu[component_id] += m_comp_h_samp[component_id]; + } + } + } + } + + transform_mcu(mcu_row); + } + + if (m_comps_in_scan == 1) + m_block_y_mcu[m_comp_list[0]]++; + else + { + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + component_id = m_comp_list[component_num]; + + m_block_y_mcu[component_id] += m_comp_v_samp[component_id]; + } + } + } + + // Restart interval processing. + void jpeg_decoder::process_restart() + { + int i; + int c = 0; + + // Align to a byte boundry + // FIXME: Is this really necessary? get_bits_no_markers() never reads in markers! + //get_bits_no_markers(m_bits_left & 7); + + // Let's scan a little bit to find the marker, but not _too_ far. + // 1536 is a "fudge factor" that determines how much to scan. + for (i = 1536; i > 0; i--) + if (get_char() == 0xFF) + break; + + if (i == 0) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + for (; i > 0; i--) + if ((c = get_char()) != 0xFF) + break; + + if (i == 0) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + // Is it the expected marker? If not, something bad happened. + if (c != (m_next_restart_num + M_RST0)) + stop_decoding(JPGD_BAD_RESTART_MARKER); + + // Reset each component's DC prediction values. + memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint)); + + m_eob_run = 0; + + m_restarts_left = m_restart_interval; + + m_next_restart_num = (m_next_restart_num + 1) & 7; + + // Get the bit buffer going again... + + m_bits_left = 16; + get_bits_no_markers(16); + get_bits_no_markers(16); + } + + static inline int dequantize_ac(int c, int q) { c *= q; return c; } + + // Decodes and dequantizes the next row of coefficients. + void jpeg_decoder::decode_next_row() + { + int row_block = 0; + + for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + if ((m_restart_interval) && (m_restarts_left == 0)) + process_restart(); + + jpgd_block_coeff_t* p = m_pMCU_coefficients; + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64) + { + int component_id = m_mcu_org[mcu_block]; + if (m_comp_quant[component_id] >= JPGD_MAX_QUANT_TABLES) + stop_decoding(JPGD_DECODE_ERROR); + + jpgd_quant_t* q = m_quant[m_comp_quant[component_id]]; + + int r, s; + s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r); + if (s >= 16) + stop_decoding(JPGD_DECODE_ERROR); + + s = JPGD_HUFF_EXTEND(r, s); + + m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]); + + p[0] = static_cast(s * q[0]); + + int prev_num_set = m_mcu_block_max_zag[mcu_block]; + + huff_tables* pH = m_pHuff_tabs[m_comp_ac_tab[component_id]]; + + int k; + for (k = 1; k < 64; k++) + { + int extra_bits; + s = huff_decode(pH, extra_bits); + + r = s >> 4; + s &= 15; + + if (s) + { + if (r) + { + if ((k + r) > 63) + stop_decoding(JPGD_DECODE_ERROR); + + if (k < prev_num_set) + { + int n = JPGD_MIN(r, prev_num_set - k); + int kt = k; + while (n--) + p[g_ZAG[kt++]] = 0; + } + + k += r; + } + + s = JPGD_HUFF_EXTEND(extra_bits, s); + + if (k >= 64) + stop_decoding(JPGD_DECODE_ERROR); + + p[g_ZAG[k]] = static_cast(dequantize_ac(s, q[k])); //s * q[k]; + } + else + { + if (r == 15) + { + if ((k + 16) > 64) + stop_decoding(JPGD_DECODE_ERROR); + + if (k < prev_num_set) + { + int n = JPGD_MIN(16, prev_num_set - k); + int kt = k; + while (n--) + { + if (kt > 63) + stop_decoding(JPGD_DECODE_ERROR); + p[g_ZAG[kt++]] = 0; + } + } + + k += 16 - 1; // - 1 because the loop counter is k + + if (p[g_ZAG[k & 63]] != 0) + stop_decoding(JPGD_DECODE_ERROR); + } + else + break; + } + } + + if (k < prev_num_set) + { + int kt = k; + while (kt < prev_num_set) + p[g_ZAG[kt++]] = 0; + } + + m_mcu_block_max_zag[mcu_block] = k; + + row_block++; + } + + transform_mcu(mcu_row); + + m_restarts_left--; + } + } + + // YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB + void jpeg_decoder::H1V1Convert() + { + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8* d = m_pScan_line_0; + uint8* s = m_pSample_buf + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int j = 0; j < 8; j++) + { + int y = s[j]; + int cb = s[64 + j]; + int cr = s[128 + j]; + + d[0] = clamp(y + m_crr[cr]); + d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16)); + d[2] = clamp(y + m_cbb[cb]); + d[3] = 255; + + d += 4; + } + + s += 64 * 3; + } + } + + // YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB + void jpeg_decoder::H2V1Convert() + { + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8* d0 = m_pScan_line_0; + uint8* y = m_pSample_buf + row * 8; + uint8* c = m_pSample_buf + 2 * 64 + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int l = 0; l < 2; l++) + { + for (int j = 0; j < 4; j++) + { + int cb = c[0]; + int cr = c[64]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j << 1]; + d0[0] = clamp(yy + rc); + d0[1] = clamp(yy + gc); + d0[2] = clamp(yy + bc); + d0[3] = 255; + + yy = y[(j << 1) + 1]; + d0[4] = clamp(yy + rc); + d0[5] = clamp(yy + gc); + d0[6] = clamp(yy + bc); + d0[7] = 255; + + d0 += 8; + + c++; + } + y += 64; + } + + y += 64 * 4 - 64 * 2; + c += 64 * 4 - 8; + } + } + + // YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB + void jpeg_decoder::H2V1ConvertFiltered() + { + const uint BLOCKS_PER_MCU = 4; + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8* d0 = m_pScan_line_0; + + const int half_image_x_size = (m_image_x_size >> 1) - 1; + const int row_x8 = row * 8; + + for (int x = 0; x < m_image_x_size; x++) + { + int y = m_pSample_buf[check_sample_buf_ofs((x >> 4) * BLOCKS_PER_MCU * 64 + ((x & 8) ? 64 : 0) + (x & 7) + row_x8)]; + + int c_x0 = (x - 1) >> 1; + int c_x1 = JPGD_MIN(c_x0 + 1, half_image_x_size); + c_x0 = JPGD_MAX(c_x0, 0); + + int a = (c_x0 >> 3) * BLOCKS_PER_MCU * 64 + (c_x0 & 7) + row_x8 + 128; + int cb0 = m_pSample_buf[check_sample_buf_ofs(a)]; + int cr0 = m_pSample_buf[check_sample_buf_ofs(a + 64)]; + + int b = (c_x1 >> 3) * BLOCKS_PER_MCU * 64 + (c_x1 & 7) + row_x8 + 128; + int cb1 = m_pSample_buf[check_sample_buf_ofs(b)]; + int cr1 = m_pSample_buf[check_sample_buf_ofs(b + 64)]; + + int w0 = (x & 1) ? 3 : 1; + int w1 = (x & 1) ? 1 : 3; + + int cb = (cb0 * w0 + cb1 * w1 + 2) >> 2; + int cr = (cr0 * w0 + cr1 * w1 + 2) >> 2; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d0[0] = clamp(y + rc); + d0[1] = clamp(y + gc); + d0[2] = clamp(y + bc); + d0[3] = 255; + + d0 += 4; + } + } + + // YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB + void jpeg_decoder::H1V2Convert() + { + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8* d0 = m_pScan_line_0; + uint8* d1 = m_pScan_line_1; + uint8* y; + uint8* c; + + if (row < 8) + y = m_pSample_buf + row * 8; + else + y = m_pSample_buf + 64 * 1 + (row & 7) * 8; + + c = m_pSample_buf + 64 * 2 + (row >> 1) * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int j = 0; j < 8; j++) + { + int cb = c[0 + j]; + int cr = c[64 + j]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j]; + d0[0] = clamp(yy + rc); + d0[1] = clamp(yy + gc); + d0[2] = clamp(yy + bc); + d0[3] = 255; + + yy = y[8 + j]; + d1[0] = clamp(yy + rc); + d1[1] = clamp(yy + gc); + d1[2] = clamp(yy + bc); + d1[3] = 255; + + d0 += 4; + d1 += 4; + } + + y += 64 * 4; + c += 64 * 4; + } + } + + // YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB + void jpeg_decoder::H1V2ConvertFiltered() + { + const uint BLOCKS_PER_MCU = 4; + int y = m_image_y_size - m_total_lines_left; + int row = y & 15; + + const int half_image_y_size = (m_image_y_size >> 1) - 1; + + uint8* d0 = m_pScan_line_0; + + const int w0 = (row & 1) ? 3 : 1; + const int w1 = (row & 1) ? 1 : 3; + + int c_y0 = (y - 1) >> 1; + int c_y1 = JPGD_MIN(c_y0 + 1, half_image_y_size); + + const uint8_t* p_YSamples = m_pSample_buf; + const uint8_t* p_C0Samples = m_pSample_buf; + if ((c_y0 >= 0) && (((row & 15) == 0) || ((row & 15) == 15)) && (m_total_lines_left > 1)) + { + assert(y > 0); + assert(m_sample_buf_prev_valid); + + if ((row & 15) == 15) + p_YSamples = m_pSample_buf_prev; + + p_C0Samples = m_pSample_buf_prev; + } + + const int y_sample_base_ofs = ((row & 8) ? 64 : 0) + (row & 7) * 8; + const int y0_base = (c_y0 & 7) * 8 + 128; + const int y1_base = (c_y1 & 7) * 8 + 128; + + for (int x = 0; x < m_image_x_size; x++) + { + const int base_ofs = (x >> 3) * BLOCKS_PER_MCU * 64 + (x & 7); + + int y_sample = p_YSamples[check_sample_buf_ofs(base_ofs + y_sample_base_ofs)]; + + int a = base_ofs + y0_base; + int cb0_sample = p_C0Samples[check_sample_buf_ofs(a)]; + int cr0_sample = p_C0Samples[check_sample_buf_ofs(a + 64)]; + + int b = base_ofs + y1_base; + int cb1_sample = m_pSample_buf[check_sample_buf_ofs(b)]; + int cr1_sample = m_pSample_buf[check_sample_buf_ofs(b + 64)]; + + int cb = (cb0_sample * w0 + cb1_sample * w1 + 2) >> 2; + int cr = (cr0_sample * w0 + cr1_sample * w1 + 2) >> 2; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d0[0] = clamp(y_sample + rc); + d0[1] = clamp(y_sample + gc); + d0[2] = clamp(y_sample + bc); + d0[3] = 255; + + d0 += 4; + } + } + + // YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB + void jpeg_decoder::H2V2Convert() + { + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8* d0 = m_pScan_line_0; + uint8* d1 = m_pScan_line_1; + uint8* y; + uint8* c; + + if (row < 8) + y = m_pSample_buf + row * 8; + else + y = m_pSample_buf + 64 * 2 + (row & 7) * 8; + + c = m_pSample_buf + 64 * 4 + (row >> 1) * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + for (int l = 0; l < 2; l++) + { + for (int j = 0; j < 8; j += 2) + { + int cb = c[0]; + int cr = c[64]; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + int yy = y[j]; + d0[0] = clamp(yy + rc); + d0[1] = clamp(yy + gc); + d0[2] = clamp(yy + bc); + d0[3] = 255; + + yy = y[j + 1]; + d0[4] = clamp(yy + rc); + d0[5] = clamp(yy + gc); + d0[6] = clamp(yy + bc); + d0[7] = 255; + + yy = y[j + 8]; + d1[0] = clamp(yy + rc); + d1[1] = clamp(yy + gc); + d1[2] = clamp(yy + bc); + d1[3] = 255; + + yy = y[j + 8 + 1]; + d1[4] = clamp(yy + rc); + d1[5] = clamp(yy + gc); + d1[6] = clamp(yy + bc); + d1[7] = 255; + + d0 += 8; + d1 += 8; + + c++; + } + y += 64; + } + + y += 64 * 6 - 64 * 2; + c += 64 * 6 - 8; + } + } + + uint32_t jpeg_decoder::H2V2ConvertFiltered() + { + const uint BLOCKS_PER_MCU = 6; + int y = m_image_y_size - m_total_lines_left; + int row = y & 15; + + const int half_image_y_size = (m_image_y_size >> 1) - 1; + + uint8* d0 = m_pScan_line_0; + + int c_y0 = (y - 1) >> 1; + int c_y1 = JPGD_MIN(c_y0 + 1, half_image_y_size); + + const uint8_t* p_YSamples = m_pSample_buf; + const uint8_t* p_C0Samples = m_pSample_buf; + if ((c_y0 >= 0) && (((row & 15) == 0) || ((row & 15) == 15)) && (m_total_lines_left > 1)) + { + assert(y > 0); + assert(m_sample_buf_prev_valid); + + if ((row & 15) == 15) + p_YSamples = m_pSample_buf_prev; + + p_C0Samples = m_pSample_buf_prev; + } + + const int y_sample_base_ofs = ((row & 8) ? 128 : 0) + (row & 7) * 8; + const int y0_base = (c_y0 & 7) * 8 + 256; + const int y1_base = (c_y1 & 7) * 8 + 256; + + const int half_image_x_size = (m_image_x_size >> 1) - 1; + + static const uint8_t s_muls[2][2][4] = + { + { { 1, 3, 3, 9 }, { 3, 9, 1, 3 }, }, + { { 3, 1, 9, 3 }, { 9, 3, 3, 1 } } + }; + + if (((row & 15) >= 1) && ((row & 15) <= 14)) + { + assert((row & 1) == 1); + assert(((y + 1 - 1) >> 1) == c_y0); + + assert(p_YSamples == m_pSample_buf); + assert(p_C0Samples == m_pSample_buf); + + uint8* d1 = m_pScan_line_1; + const int y_sample_base_ofs1 = (((row + 1) & 8) ? 128 : 0) + ((row + 1) & 7) * 8; + + for (int x = 0; x < m_image_x_size; x++) + { + int k = (x >> 4) * BLOCKS_PER_MCU * 64 + ((x & 8) ? 64 : 0) + (x & 7); + int y_sample0 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs)]; + int y_sample1 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs1)]; + + int c_x0 = (x - 1) >> 1; + int c_x1 = JPGD_MIN(c_x0 + 1, half_image_x_size); + c_x0 = JPGD_MAX(c_x0, 0); + + int a = (c_x0 >> 3) * BLOCKS_PER_MCU * 64 + (c_x0 & 7); + int cb00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base)]; + int cr00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base + 64)]; + + int cb01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base)]; + int cr01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base + 64)]; + + int b = (c_x1 >> 3) * BLOCKS_PER_MCU * 64 + (c_x1 & 7); + int cb10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base)]; + int cr10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base + 64)]; + + int cb11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base)]; + int cr11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base + 64)]; + + { + const uint8_t* pMuls = &s_muls[row & 1][x & 1][0]; + int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4; + int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d0[0] = clamp(y_sample0 + rc); + d0[1] = clamp(y_sample0 + gc); + d0[2] = clamp(y_sample0 + bc); + d0[3] = 255; + + d0 += 4; + } + + { + const uint8_t* pMuls = &s_muls[(row + 1) & 1][x & 1][0]; + int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4; + int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d1[0] = clamp(y_sample1 + rc); + d1[1] = clamp(y_sample1 + gc); + d1[2] = clamp(y_sample1 + bc); + d1[3] = 255; + + d1 += 4; + } + + if (((x & 1) == 1) && (x < m_image_x_size - 1)) + { + const int nx = x + 1; + assert(c_x0 == (nx - 1) >> 1); + + k = (nx >> 4) * BLOCKS_PER_MCU * 64 + ((nx & 8) ? 64 : 0) + (nx & 7); + y_sample0 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs)]; + y_sample1 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs1)]; + + { + const uint8_t* pMuls = &s_muls[row & 1][nx & 1][0]; + int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4; + int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d0[0] = clamp(y_sample0 + rc); + d0[1] = clamp(y_sample0 + gc); + d0[2] = clamp(y_sample0 + bc); + d0[3] = 255; + + d0 += 4; + } + + { + const uint8_t* pMuls = &s_muls[(row + 1) & 1][nx & 1][0]; + int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4; + int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d1[0] = clamp(y_sample1 + rc); + d1[1] = clamp(y_sample1 + gc); + d1[2] = clamp(y_sample1 + bc); + d1[3] = 255; + + d1 += 4; + } + + ++x; + } + } + + return 2; + } + else + { + for (int x = 0; x < m_image_x_size; x++) + { + int y_sample = p_YSamples[check_sample_buf_ofs((x >> 4) * BLOCKS_PER_MCU * 64 + ((x & 8) ? 64 : 0) + (x & 7) + y_sample_base_ofs)]; + + int c_x0 = (x - 1) >> 1; + int c_x1 = JPGD_MIN(c_x0 + 1, half_image_x_size); + c_x0 = JPGD_MAX(c_x0, 0); + + int a = (c_x0 >> 3) * BLOCKS_PER_MCU * 64 + (c_x0 & 7); + int cb00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base)]; + int cr00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base + 64)]; + + int cb01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base)]; + int cr01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base + 64)]; + + int b = (c_x1 >> 3) * BLOCKS_PER_MCU * 64 + (c_x1 & 7); + int cb10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base)]; + int cr10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base + 64)]; + + int cb11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base)]; + int cr11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base + 64)]; + + const uint8_t* pMuls = &s_muls[row & 1][x & 1][0]; + int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4; + int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4; + + int rc = m_crr[cr]; + int gc = ((m_crg[cr] + m_cbg[cb]) >> 16); + int bc = m_cbb[cb]; + + d0[0] = clamp(y_sample + rc); + d0[1] = clamp(y_sample + gc); + d0[2] = clamp(y_sample + bc); + d0[3] = 255; + + d0 += 4; + } + + return 1; + } + } + + // Y (1 block per MCU) to 8-bit grayscale + void jpeg_decoder::gray_convert() + { + int row = m_max_mcu_y_size - m_mcu_lines_left; + uint8* d = m_pScan_line_0; + uint8* s = m_pSample_buf + row * 8; + + for (int i = m_max_mcus_per_row; i > 0; i--) + { + *(uint*)d = *(uint*)s; + *(uint*)(&d[4]) = *(uint*)(&s[4]); + + s += 64; + d += 8; + } + } + + // Find end of image (EOI) marker, so we can return to the user the exact size of the input stream. + void jpeg_decoder::find_eoi() + { + if (!m_progressive_flag) + { + // Attempt to read the EOI marker. + //get_bits_no_markers(m_bits_left & 7); + + // Prime the bit buffer + m_bits_left = 16; + get_bits(16); + get_bits(16); + + // The next marker _should_ be EOI + process_markers(); + } + + m_total_bytes_read -= m_in_buf_left; + } + + int jpeg_decoder::decode_next_mcu_row() + { + if (::setjmp(m_jmp_state)) + return JPGD_FAILED; + + const bool chroma_y_filtering = ((m_flags & cFlagBoxChromaFiltering) == 0) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2)); + if (chroma_y_filtering) + { + std::swap(m_pSample_buf, m_pSample_buf_prev); + + m_sample_buf_prev_valid = true; + } + + if (m_progressive_flag) + load_next_row(); + else + decode_next_row(); + + // Find the EOI marker if that was the last row. + if (m_total_lines_left <= m_max_mcu_y_size) + find_eoi(); + + m_mcu_lines_left = m_max_mcu_y_size; + return 0; + } + + int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len) + { + if ((m_error_code) || (!m_ready_flag)) + return JPGD_FAILED; + + if (m_total_lines_left == 0) + return JPGD_DONE; + + const bool chroma_y_filtering = ((m_flags & cFlagBoxChromaFiltering) == 0) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2)); + + bool get_another_mcu_row = false; + bool got_mcu_early = false; + if (chroma_y_filtering) + { + if (m_total_lines_left == m_image_y_size) + get_another_mcu_row = true; + else if ((m_mcu_lines_left == 1) && (m_total_lines_left > 1)) + { + get_another_mcu_row = true; + got_mcu_early = true; + } + } + else + { + get_another_mcu_row = (m_mcu_lines_left == 0); + } + + if (get_another_mcu_row) + { + int status = decode_next_mcu_row(); + if (status != 0) + return status; + } + + switch (m_scan_type) + { + case JPGD_YH2V2: + { + if ((m_flags & cFlagBoxChromaFiltering) == 0) + { + if (m_num_buffered_scanlines == 1) + { + *pScan_line = m_pScan_line_1; + } + else if (m_num_buffered_scanlines == 0) + { + m_num_buffered_scanlines = H2V2ConvertFiltered(); + *pScan_line = m_pScan_line_0; + } + + m_num_buffered_scanlines--; + } + else + { + if ((m_mcu_lines_left & 1) == 0) + { + H2V2Convert(); + *pScan_line = m_pScan_line_0; + } + else + *pScan_line = m_pScan_line_1; + } + + break; + } + case JPGD_YH2V1: + { + if ((m_flags & cFlagBoxChromaFiltering) == 0) + H2V1ConvertFiltered(); + else + H2V1Convert(); + *pScan_line = m_pScan_line_0; + break; + } + case JPGD_YH1V2: + { + if (chroma_y_filtering) + { + H1V2ConvertFiltered(); + *pScan_line = m_pScan_line_0; + } + else + { + if ((m_mcu_lines_left & 1) == 0) + { + H1V2Convert(); + *pScan_line = m_pScan_line_0; + } + else + *pScan_line = m_pScan_line_1; + } + + break; + } + case JPGD_YH1V1: + { + H1V1Convert(); + *pScan_line = m_pScan_line_0; + break; + } + case JPGD_GRAYSCALE: + { + gray_convert(); + *pScan_line = m_pScan_line_0; + + break; + } + } + + *pScan_line_len = m_real_dest_bytes_per_scan_line; + + if (!got_mcu_early) + { + m_mcu_lines_left--; + } + + m_total_lines_left--; + + return JPGD_SUCCESS; + } + + // Creates the tables needed for efficient Huffman decoding. + void jpeg_decoder::make_huff_table(int index, huff_tables* pH) + { + int p, i, l, si; + uint8 huffsize[258]; + uint huffcode[258]; + uint code; + uint subtree; + int code_size; + int lastp; + int nextfreeentry; + int currententry; + + pH->ac_table = m_huff_ac[index] != 0; + + p = 0; + + for (l = 1; l <= 16; l++) + { + for (i = 1; i <= m_huff_num[index][l]; i++) + { + if (p >= 257) + stop_decoding(JPGD_DECODE_ERROR); + huffsize[p++] = static_cast(l); + } + } + + assert(p < 258); + huffsize[p] = 0; + + lastp = p; + + code = 0; + si = huffsize[0]; + p = 0; + + while (huffsize[p]) + { + while (huffsize[p] == si) + { + if (p >= 257) + stop_decoding(JPGD_DECODE_ERROR); + huffcode[p++] = code; + code++; + } + + code <<= 1; + si++; + } + + memset(pH->look_up, 0, sizeof(pH->look_up)); + memset(pH->look_up2, 0, sizeof(pH->look_up2)); + memset(pH->tree, 0, sizeof(pH->tree)); + memset(pH->code_size, 0, sizeof(pH->code_size)); + + nextfreeentry = -1; + + p = 0; + + while (p < lastp) + { + i = m_huff_val[index][p]; + + code = huffcode[p]; + code_size = huffsize[p]; + + assert(i < JPGD_HUFF_CODE_SIZE_MAX_LENGTH); + pH->code_size[i] = static_cast(code_size); + + if (code_size <= 8) + { + code <<= (8 - code_size); + + for (l = 1 << (8 - code_size); l > 0; l--) + { + if (code >= 256) + stop_decoding(JPGD_DECODE_ERROR); + + pH->look_up[code] = i; + + bool has_extrabits = false; + int extra_bits = 0; + int num_extra_bits = i & 15; + + int bits_to_fetch = code_size; + if (num_extra_bits) + { + int total_codesize = code_size + num_extra_bits; + if (total_codesize <= 8) + { + has_extrabits = true; + extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize)); + + if (extra_bits > 0x7FFF) + stop_decoding(JPGD_DECODE_ERROR); + + bits_to_fetch += num_extra_bits; + } + } + + if (!has_extrabits) + pH->look_up2[code] = i | (bits_to_fetch << 8); + else + pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8); + + code++; + } + } + else + { + subtree = (code >> (code_size - 8)) & 0xFF; + + currententry = pH->look_up[subtree]; + + if (currententry == 0) + { + pH->look_up[subtree] = currententry = nextfreeentry; + pH->look_up2[subtree] = currententry = nextfreeentry; + + nextfreeentry -= 2; + } + + code <<= (16 - (code_size - 8)); + + for (l = code_size; l > 9; l--) + { + if ((code & 0x8000) == 0) + currententry--; + + unsigned int idx = -currententry - 1; + + if (idx >= JPGD_HUFF_TREE_MAX_LENGTH) + stop_decoding(JPGD_DECODE_ERROR); + + if (pH->tree[idx] == 0) + { + pH->tree[idx] = nextfreeentry; + + currententry = nextfreeentry; + + nextfreeentry -= 2; + } + else + { + currententry = pH->tree[idx]; + } + + code <<= 1; + } + + if ((code & 0x8000) == 0) + currententry--; + + if ((-currententry - 1) >= JPGD_HUFF_TREE_MAX_LENGTH) + stop_decoding(JPGD_DECODE_ERROR); + + pH->tree[-currententry - 1] = i; + } + + p++; + } + } + + // Verifies the quantization tables needed for this scan are available. + void jpeg_decoder::check_quant_tables() + { + for (int i = 0; i < m_comps_in_scan; i++) + if (m_quant[m_comp_quant[m_comp_list[i]]] == NULL) + stop_decoding(JPGD_UNDEFINED_QUANT_TABLE); + } + + // Verifies that all the Huffman tables needed for this scan are available. + void jpeg_decoder::check_huff_tables() + { + for (int i = 0; i < m_comps_in_scan; i++) + { + if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == NULL)) + stop_decoding(JPGD_UNDEFINED_HUFF_TABLE); + + if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == NULL)) + stop_decoding(JPGD_UNDEFINED_HUFF_TABLE); + } + + for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++) + if (m_huff_num[i]) + { + if (!m_pHuff_tabs[i]) + m_pHuff_tabs[i] = (huff_tables*)alloc(sizeof(huff_tables)); + + make_huff_table(i, m_pHuff_tabs[i]); + } + } + + // Determines the component order inside each MCU. + // Also calcs how many MCU's are on each row, etc. + bool jpeg_decoder::calc_mcu_block_order() + { + int component_num, component_id; + int max_h_samp = 0, max_v_samp = 0; + + for (component_id = 0; component_id < m_comps_in_frame; component_id++) + { + if (m_comp_h_samp[component_id] > max_h_samp) + max_h_samp = m_comp_h_samp[component_id]; + + if (m_comp_v_samp[component_id] > max_v_samp) + max_v_samp = m_comp_v_samp[component_id]; + } + + for (component_id = 0; component_id < m_comps_in_frame; component_id++) + { + m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8; + m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8; + } + + if (m_comps_in_scan == 1) + { + m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]]; + m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]]; + } + else + { + m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp; + m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp; + } + + if (m_comps_in_scan == 1) + { + m_mcu_org[0] = m_comp_list[0]; + + m_blocks_per_mcu = 1; + } + else + { + m_blocks_per_mcu = 0; + + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + int num_blocks; + + component_id = m_comp_list[component_num]; + + num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id]; + + while (num_blocks--) + m_mcu_org[m_blocks_per_mcu++] = component_id; + } + } + + if (m_blocks_per_mcu > m_max_blocks_per_mcu) + return false; + + for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + int comp_id = m_mcu_org[mcu_block]; + if (comp_id >= JPGD_MAX_QUANT_TABLES) + return false; + } + + return true; + } + + // Starts a new scan. + int jpeg_decoder::init_scan() + { + if (!locate_sos_marker()) + return JPGD_FALSE; + + if (!calc_mcu_block_order()) + return JPGD_FALSE; + + check_huff_tables(); + + check_quant_tables(); + + memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint)); + + m_eob_run = 0; + + if (m_restart_interval) + { + m_restarts_left = m_restart_interval; + m_next_restart_num = 0; + } + + fix_in_buffer(); + + return JPGD_TRUE; + } + + // Starts a frame. Determines if the number of components or sampling factors + // are supported. + void jpeg_decoder::init_frame() + { + int i; + + if (m_comps_in_frame == 1) + { + if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1)) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + m_scan_type = JPGD_GRAYSCALE; + m_max_blocks_per_mcu = 1; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 8; + } + else if (m_comps_in_frame == 3) + { + if (((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) || + ((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1))) + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + + if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1)) + { + m_scan_type = JPGD_YH1V1; + + m_max_blocks_per_mcu = 3; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 8; + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1)) + { + m_scan_type = JPGD_YH2V1; + m_max_blocks_per_mcu = 4; + m_max_mcu_x_size = 16; + m_max_mcu_y_size = 8; + } + else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2)) + { + m_scan_type = JPGD_YH1V2; + m_max_blocks_per_mcu = 4; + m_max_mcu_x_size = 8; + m_max_mcu_y_size = 16; + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2)) + { + m_scan_type = JPGD_YH2V2; + m_max_blocks_per_mcu = 6; + m_max_mcu_x_size = 16; + m_max_mcu_y_size = 16; + } + else + stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS); + } + else + stop_decoding(JPGD_UNSUPPORTED_COLORSPACE); + + m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size; + m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size; + + // These values are for the *destination* pixels: after conversion. + if (m_scan_type == JPGD_GRAYSCALE) + m_dest_bytes_per_pixel = 1; + else + m_dest_bytes_per_pixel = 4; + + m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel; + + m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel); + + // Initialize two scan line buffers. + m_pScan_line_0 = (uint8*)alloc_aligned(m_dest_bytes_per_scan_line, true); + if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2)) + m_pScan_line_1 = (uint8*)alloc_aligned(m_dest_bytes_per_scan_line, true); + + m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu; + + // Should never happen + if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW) + stop_decoding(JPGD_DECODE_ERROR); + + // Allocate the coefficient buffer, enough for one MCU + m_pMCU_coefficients = (jpgd_block_coeff_t *)alloc_aligned(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_coeff_t)); + + for (i = 0; i < m_max_blocks_per_mcu; i++) + m_mcu_block_max_zag[i] = 64; + + m_pSample_buf = (uint8*)alloc_aligned(m_max_blocks_per_row * 64); + m_pSample_buf_prev = (uint8*)alloc_aligned(m_max_blocks_per_row * 64); + + m_total_lines_left = m_image_y_size; + + m_mcu_lines_left = 0; + + create_look_ups(); + } + + // The coeff_buf series of methods originally stored the coefficients + // into a "virtual" file which was located in EMS, XMS, or a disk file. A cache + // was used to make this process more efficient. Now, we can store the entire + // thing in RAM. + jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y) + { + coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf)); + + cb->block_num_x = block_num_x; + cb->block_num_y = block_num_y; + cb->block_len_x = block_len_x; + cb->block_len_y = block_len_y; + cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_coeff_t); + cb->pData = (uint8*)alloc(cb->block_size * block_num_x * block_num_y, true); + return cb; + } + + inline jpgd_block_coeff_t* jpeg_decoder::coeff_buf_getp(coeff_buf* cb, int block_x, int block_y) + { + if ((block_x >= cb->block_num_x) || (block_y >= cb->block_num_y)) + stop_decoding(JPGD_DECODE_ERROR); + + return (jpgd_block_coeff_t*)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x)); + } + + // The following methods decode the various types of m_blocks encountered + // in progressively encoded images. + void jpeg_decoder::decode_block_dc_first(jpeg_decoder* pD, int component_id, int block_x, int block_y) + { + int s, r; + jpgd_block_coeff_t* p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y); + + if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0) + { + if (s >= 16) + pD->stop_decoding(JPGD_DECODE_ERROR); + + r = pD->get_bits_no_markers(s); + s = JPGD_HUFF_EXTEND(r, s); + } + + pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]); + + p[0] = static_cast(s << pD->m_successive_low); + } + + void jpeg_decoder::decode_block_dc_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y) + { + if (pD->get_bits_no_markers(1)) + { + jpgd_block_coeff_t* p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y); + + p[0] |= (1 << pD->m_successive_low); + } + } + + void jpeg_decoder::decode_block_ac_first(jpeg_decoder* pD, int component_id, int block_x, int block_y) + { + int k, s, r; + + if (pD->m_eob_run) + { + pD->m_eob_run--; + return; + } + + jpgd_block_coeff_t* p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); + + for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++) + { + unsigned int idx = pD->m_comp_ac_tab[component_id]; + if (idx >= JPGD_MAX_HUFF_TABLES) + pD->stop_decoding(JPGD_DECODE_ERROR); + + s = pD->huff_decode(pD->m_pHuff_tabs[idx]); + + r = s >> 4; + s &= 15; + + if (s) + { + if ((k += r) > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + + r = pD->get_bits_no_markers(s); + s = JPGD_HUFF_EXTEND(r, s); + + p[g_ZAG[k]] = static_cast(s << pD->m_successive_low); + } + else + { + if (r == 15) + { + if ((k += 15) > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + } + else + { + pD->m_eob_run = 1 << r; + + if (r) + pD->m_eob_run += pD->get_bits_no_markers(r); + + pD->m_eob_run--; + + break; + } + } + } + } + + void jpeg_decoder::decode_block_ac_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y) + { + int s, k, r; + + int p1 = 1 << pD->m_successive_low; + + //int m1 = (-1) << pD->m_successive_low; + int m1 = static_cast((4294967295U << pD->m_successive_low)); + + jpgd_block_coeff_t* p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); + if (pD->m_spectral_end > 63) + pD->stop_decoding(JPGD_DECODE_ERROR); + + k = pD->m_spectral_start; + + if (pD->m_eob_run == 0) + { + for (; k <= pD->m_spectral_end; k++) + { + unsigned int idx = pD->m_comp_ac_tab[component_id]; + if (idx >= JPGD_MAX_HUFF_TABLES) + pD->stop_decoding(JPGD_DECODE_ERROR); + + s = pD->huff_decode(pD->m_pHuff_tabs[idx]); + + r = s >> 4; + s &= 15; + + if (s) + { + if (s != 1) + pD->stop_decoding(JPGD_DECODE_ERROR); + + if (pD->get_bits_no_markers(1)) + s = p1; + else + s = m1; + } + else + { + if (r != 15) + { + pD->m_eob_run = 1 << r; + + if (r) + pD->m_eob_run += pD->get_bits_no_markers(r); + + break; + } + } + + do + { + jpgd_block_coeff_t* this_coef = p + g_ZAG[k & 63]; + + if (*this_coef != 0) + { + if (pD->get_bits_no_markers(1)) + { + if ((*this_coef & p1) == 0) + { + if (*this_coef >= 0) + *this_coef = static_cast(*this_coef + p1); + else + *this_coef = static_cast(*this_coef + m1); + } + } + } + else + { + if (--r < 0) + break; + } + + k++; + + } while (k <= pD->m_spectral_end); + + if ((s) && (k < 64)) + { + p[g_ZAG[k]] = static_cast(s); + } + } + } + + if (pD->m_eob_run > 0) + { + for (; k <= pD->m_spectral_end; k++) + { + jpgd_block_coeff_t* this_coef = p + g_ZAG[k & 63]; // logical AND to shut up static code analysis + + if (*this_coef != 0) + { + if (pD->get_bits_no_markers(1)) + { + if ((*this_coef & p1) == 0) + { + if (*this_coef >= 0) + *this_coef = static_cast(*this_coef + p1); + else + *this_coef = static_cast(*this_coef + m1); + } + } + } + } + + pD->m_eob_run--; + } + } + + // Decode a scan in a progressively encoded image. + void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func) + { + int mcu_row, mcu_col, mcu_block; + int block_x_mcu[JPGD_MAX_COMPONENTS], block_y_mcu[JPGD_MAX_COMPONENTS]; + + memset(block_y_mcu, 0, sizeof(block_y_mcu)); + + for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++) + { + int component_num, component_id; + + memset(block_x_mcu, 0, sizeof(block_x_mcu)); + + for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++) + { + int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0; + + if ((m_restart_interval) && (m_restarts_left == 0)) + process_restart(); + + for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++) + { + component_id = m_mcu_org[mcu_block]; + + decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, block_y_mcu[component_id] + block_y_mcu_ofs); + + if (m_comps_in_scan == 1) + block_x_mcu[component_id]++; + else + { + if (++block_x_mcu_ofs == m_comp_h_samp[component_id]) + { + block_x_mcu_ofs = 0; + + if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) + { + block_y_mcu_ofs = 0; + block_x_mcu[component_id] += m_comp_h_samp[component_id]; + } + } + } + } + + m_restarts_left--; + } + + if (m_comps_in_scan == 1) + block_y_mcu[m_comp_list[0]]++; + else + { + for (component_num = 0; component_num < m_comps_in_scan; component_num++) + { + component_id = m_comp_list[component_num]; + block_y_mcu[component_id] += m_comp_v_samp[component_id]; + } + } + } + } + + // Decode a progressively encoded image. + void jpeg_decoder::init_progressive() + { + int i; + + if (m_comps_in_frame == 4) + stop_decoding(JPGD_UNSUPPORTED_COLORSPACE); + + // Allocate the coefficient buffers. + for (i = 0; i < m_comps_in_frame; i++) + { + m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1); + m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8); + } + + // See https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf + uint32_t total_scans = 0; + const uint32_t MAX_SCANS_TO_PROCESS = 1000; + + for (; ; ) + { + int dc_only_scan, refinement_scan; + pDecode_block_func decode_block_func; + + if (!init_scan()) + break; + + dc_only_scan = (m_spectral_start == 0); + refinement_scan = (m_successive_high != 0); + + if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63)) + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + + if (dc_only_scan) + { + if (m_spectral_end) + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + } + else if (m_comps_in_scan != 1) /* AC scans can only contain one component */ + stop_decoding(JPGD_BAD_SOS_SPECTRAL); + + if ((refinement_scan) && (m_successive_low != m_successive_high - 1)) + stop_decoding(JPGD_BAD_SOS_SUCCESSIVE); + + if (dc_only_scan) + { + if (refinement_scan) + decode_block_func = decode_block_dc_refine; + else + decode_block_func = decode_block_dc_first; + } + else + { + if (refinement_scan) + decode_block_func = decode_block_ac_refine; + else + decode_block_func = decode_block_ac_first; + } + + decode_scan(decode_block_func); + + m_bits_left = 16; + get_bits(16); + get_bits(16); + + total_scans++; + if (total_scans > MAX_SCANS_TO_PROCESS) + stop_decoding(JPGD_TOO_MANY_SCANS); + } + + m_comps_in_scan = m_comps_in_frame; + + for (i = 0; i < m_comps_in_frame; i++) + m_comp_list[i] = i; + + if (!calc_mcu_block_order()) + stop_decoding(JPGD_DECODE_ERROR); + } + + void jpeg_decoder::init_sequential() + { + if (!init_scan()) + stop_decoding(JPGD_UNEXPECTED_MARKER); + } + + void jpeg_decoder::decode_start() + { + init_frame(); + + if (m_progressive_flag) + init_progressive(); + else + init_sequential(); + } + + void jpeg_decoder::decode_init(jpeg_decoder_stream* pStream, uint32_t flags) + { + init(pStream, flags); + locate_sof_marker(); + } + + jpeg_decoder::jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags) + { + if (::setjmp(m_jmp_state)) + return; + decode_init(pStream, flags); + } + + int jpeg_decoder::begin_decoding() + { + if (m_ready_flag) + return JPGD_SUCCESS; + + if (m_error_code) + return JPGD_FAILED; + + if (::setjmp(m_jmp_state)) + return JPGD_FAILED; + + decode_start(); + + m_ready_flag = true; + + return JPGD_SUCCESS; + } + + jpeg_decoder::~jpeg_decoder() + { + free_all_blocks(); + } + + jpeg_decoder_file_stream::jpeg_decoder_file_stream() + { + m_pFile = NULL; + m_eof_flag = false; + m_error_flag = false; + } + + void jpeg_decoder_file_stream::close() + { + if (m_pFile) + { + fclose(m_pFile); + m_pFile = NULL; + } + + m_eof_flag = false; + m_error_flag = false; + } + + jpeg_decoder_file_stream::~jpeg_decoder_file_stream() + { + close(); + } + + bool jpeg_decoder_file_stream::open(const char* Pfilename) + { + close(); + + m_eof_flag = false; + m_error_flag = false; + +#if defined(_MSC_VER) + m_pFile = NULL; + fopen_s(&m_pFile, Pfilename, "rb"); +#else + m_pFile = fopen(Pfilename, "rb"); +#endif + return m_pFile != NULL; + } + + int jpeg_decoder_file_stream::read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag) + { + if (!m_pFile) + return -1; + + if (m_eof_flag) + { + *pEOF_flag = true; + return 0; + } + + if (m_error_flag) + return -1; + + int bytes_read = static_cast(fread(pBuf, 1, max_bytes_to_read, m_pFile)); + if (bytes_read < max_bytes_to_read) + { + if (ferror(m_pFile)) + { + m_error_flag = true; + return -1; + } + + m_eof_flag = true; + *pEOF_flag = true; + } + + return bytes_read; + } + + bool jpeg_decoder_mem_stream::open(const uint8* pSrc_data, uint size) + { + close(); + m_pSrc_data = pSrc_data; + m_ofs = 0; + m_size = size; + return true; + } + + int jpeg_decoder_mem_stream::read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag) + { + *pEOF_flag = false; + + if (!m_pSrc_data) + return -1; + + uint bytes_remaining = m_size - m_ofs; + if ((uint)max_bytes_to_read > bytes_remaining) + { + max_bytes_to_read = bytes_remaining; + *pEOF_flag = true; + } + + memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read); + m_ofs += max_bytes_to_read; + + return max_bytes_to_read; + } + + unsigned char* decompress_jpeg_image_from_stream(jpeg_decoder_stream* pStream, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags) + { + if (!actual_comps) + return NULL; + *actual_comps = 0; + + if ((!pStream) || (!width) || (!height) || (!req_comps)) + return NULL; + + if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) + return NULL; + + jpeg_decoder decoder(pStream, flags); + if (decoder.get_error_code() != JPGD_SUCCESS) + return NULL; + + const int image_width = decoder.get_width(), image_height = decoder.get_height(); + *width = image_width; + *height = image_height; + *actual_comps = decoder.get_num_components(); + + if (decoder.begin_decoding() != JPGD_SUCCESS) + return NULL; + + const int dst_bpl = image_width * req_comps; + + uint8* pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height); + if (!pImage_data) + return NULL; + + for (int y = 0; y < image_height; y++) + { + const uint8* pScan_line; + uint scan_line_len; + if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) + { + jpgd_free(pImage_data); + return NULL; + } + + uint8* pDst = pImage_data + y * dst_bpl; + + if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3))) + memcpy(pDst, pScan_line, dst_bpl); + else if (decoder.get_num_components() == 1) + { + if (req_comps == 3) + { + for (int x = 0; x < image_width; x++) + { + uint8 luma = pScan_line[x]; + pDst[0] = luma; + pDst[1] = luma; + pDst[2] = luma; + pDst += 3; + } + } + else + { + for (int x = 0; x < image_width; x++) + { + uint8 luma = pScan_line[x]; + pDst[0] = luma; + pDst[1] = luma; + pDst[2] = luma; + pDst[3] = 255; + pDst += 4; + } + } + } + else if (decoder.get_num_components() == 3) + { + if (req_comps == 1) + { + const int YR = 19595, YG = 38470, YB = 7471; + for (int x = 0; x < image_width; x++) + { + int r = pScan_line[x * 4 + 0]; + int g = pScan_line[x * 4 + 1]; + int b = pScan_line[x * 4 + 2]; + *pDst++ = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); + } + } + else + { + for (int x = 0; x < image_width; x++) + { + pDst[0] = pScan_line[x * 4 + 0]; + pDst[1] = pScan_line[x * 4 + 1]; + pDst[2] = pScan_line[x * 4 + 2]; + pDst += 3; + } + } + } + } + + return pImage_data; + } + + unsigned char* decompress_jpeg_image_from_memory(const unsigned char* pSrc_data, int src_data_size, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags) + { + jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size); + return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps, flags); + } + + unsigned char* decompress_jpeg_image_from_file(const char* pSrc_filename, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags) + { + jpgd::jpeg_decoder_file_stream file_stream; + if (!file_stream.open(pSrc_filename)) + return NULL; + return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps, flags); + } + +} // namespace jpgd diff --git a/RichgelJpeg/jpgd.h b/RichgelJpeg/jpgd.h new file mode 100644 index 0000000..3913669 --- /dev/null +++ b/RichgelJpeg/jpgd.h @@ -0,0 +1,351 @@ +// jpgd.h - C++ class for JPEG decompression. +// Richard Geldreich +// See jpgd.cpp for license (Public Domain or Apache 2.0). +#ifndef JPEG_DECODER_H +#define JPEG_DECODER_H + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#define JPGD_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) +#define JPGD_NORETURN __attribute__ ((noreturn)) +#else +#define JPGD_NORETURN +#endif + +#define JPGD_HUFF_TREE_MAX_LENGTH 512 +#define JPGD_HUFF_CODE_SIZE_MAX_LENGTH 256 + +namespace jpgd +{ + typedef unsigned char uint8; + typedef signed short int16; + typedef unsigned short uint16; + typedef unsigned int uint; + typedef signed int int32; + + // Loads a JPEG image from a memory buffer or a file. + // req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA). + // On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB). + // Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly. + // Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp. + unsigned char* decompress_jpeg_image_from_memory(const unsigned char* pSrc_data, int src_data_size, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags = 0); + unsigned char* decompress_jpeg_image_from_file(const char* pSrc_filename, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags = 0); + + // Success/failure error codes. + enum jpgd_status + { + JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1, + JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE, + JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS, + JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH, + JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER, + JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS, + JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE, + JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, + JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM, JPGD_TOO_MANY_SCANS + }; + + // Input stream interface. + // Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available. + // The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set. + // It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer. + // Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding. + class jpeg_decoder_stream + { + public: + jpeg_decoder_stream() { } + virtual ~jpeg_decoder_stream() { } + + // The read() method is called when the internal input buffer is empty. + // Parameters: + // pBuf - input buffer + // max_bytes_to_read - maximum bytes that can be written to pBuf + // pEOF_flag - set this to true if at end of stream (no more bytes remaining) + // Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0). + // Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full. + virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag) = 0; + }; + + // stdio FILE stream class. + class jpeg_decoder_file_stream : public jpeg_decoder_stream + { + jpeg_decoder_file_stream(const jpeg_decoder_file_stream&); + jpeg_decoder_file_stream& operator =(const jpeg_decoder_file_stream&); + + FILE* m_pFile; + bool m_eof_flag, m_error_flag; + + public: + jpeg_decoder_file_stream(); + virtual ~jpeg_decoder_file_stream(); + + bool open(const char* Pfilename); + void close(); + + virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag); + }; + + // Memory stream class. + class jpeg_decoder_mem_stream : public jpeg_decoder_stream + { + const uint8* m_pSrc_data; + uint m_ofs, m_size; + + public: + jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { } + jpeg_decoder_mem_stream(const uint8* pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { } + + virtual ~jpeg_decoder_mem_stream() { } + + bool open(const uint8* pSrc_data, uint size); + void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; } + + virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag); + }; + + // Loads JPEG file from a jpeg_decoder_stream. + unsigned char* decompress_jpeg_image_from_stream(jpeg_decoder_stream* pStream, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags = 0); + + enum + { + JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4, + JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 16384, JPGD_MAX_HEIGHT = 32768, JPGD_MAX_WIDTH = 32768 + }; + + typedef int16 jpgd_quant_t; + typedef int16 jpgd_block_coeff_t; + + class jpeg_decoder + { + public: + enum + { + cFlagBoxChromaFiltering = 1, + cFlagDisableSIMD = 2 + }; + + // Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc. + // methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline. + jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags = 0); + + ~jpeg_decoder(); + + // Call this method after constructing the object to begin decompression. + // If JPGD_SUCCESS is returned you may then call decode() on each scanline. + + int begin_decoding(); + + // Returns the next scan line. + // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1). + // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4). + // Returns JPGD_SUCCESS if a scan line has been returned. + // Returns JPGD_DONE if all scan lines have been returned. + // Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info. + int decode(const void** pScan_line, uint* pScan_line_len); + + inline jpgd_status get_error_code() const { return m_error_code; } + + inline int get_width() const { return m_image_x_size; } + inline int get_height() const { return m_image_y_size; } + + inline int get_num_components() const { return m_comps_in_frame; } + + inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; } + inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); } + + // Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file). + inline int get_total_bytes_read() const { return m_total_bytes_read; } + + private: + jpeg_decoder(const jpeg_decoder&); + jpeg_decoder& operator =(const jpeg_decoder&); + + typedef void (*pDecode_block_func)(jpeg_decoder*, int, int, int); + + struct huff_tables + { + bool ac_table; + uint look_up[256]; + uint look_up2[256]; + uint8 code_size[JPGD_HUFF_CODE_SIZE_MAX_LENGTH]; + uint tree[JPGD_HUFF_TREE_MAX_LENGTH]; + }; + + struct coeff_buf + { + uint8* pData; + int block_num_x, block_num_y; + int block_len_x, block_len_y; + int block_size; + }; + + struct mem_block + { + mem_block* m_pNext; + size_t m_used_count; + size_t m_size; + char m_data[1]; + }; + + jmp_buf m_jmp_state; + uint32_t m_flags; + mem_block* m_pMem_blocks; + int m_image_x_size; + int m_image_y_size; + jpeg_decoder_stream* m_pStream; + + int m_progressive_flag; + + uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES]; + uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size + uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size + jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables + int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported) + int m_comps_in_frame; // # of components in frame + int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor + int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor + int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector + int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID + int m_comp_h_blocks[JPGD_MAX_COMPONENTS]; + int m_comp_v_blocks[JPGD_MAX_COMPONENTS]; + int m_comps_in_scan; // # of components in scan + int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan + int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector + int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector + int m_spectral_start; // spectral selection start + int m_spectral_end; // spectral selection end + int m_successive_low; // successive approximation low + int m_successive_high; // successive approximation high + int m_max_mcu_x_size; // MCU's max. X size in pixels + int m_max_mcu_y_size; // MCU's max. Y size in pixels + int m_blocks_per_mcu; + int m_max_blocks_per_row; + int m_mcus_per_row, m_mcus_per_col; + int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU]; + int m_total_lines_left; // total # lines left in image + int m_mcu_lines_left; // total # lines left in this MCU + int m_num_buffered_scanlines; + int m_real_dest_bytes_per_scan_line; + int m_dest_bytes_per_scan_line; // rounded up + int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y) + huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES]; + coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS]; + coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS]; + int m_eob_run; + int m_block_y_mcu[JPGD_MAX_COMPONENTS]; + uint8* m_pIn_buf_ofs; + int m_in_buf_left; + int m_tem_flag; + + uint8 m_in_buf_pad_start[64]; + uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128]; + uint8 m_in_buf_pad_end[64]; + + int m_bits_left; + uint m_bit_buf; + int m_restart_interval; + int m_restarts_left; + int m_next_restart_num; + int m_max_mcus_per_row; + int m_max_blocks_per_mcu; + + int m_max_mcus_per_col; + uint m_last_dc_val[JPGD_MAX_COMPONENTS]; + jpgd_block_coeff_t* m_pMCU_coefficients; + int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU]; + uint8* m_pSample_buf; + uint8* m_pSample_buf_prev; + int m_crr[256]; + int m_cbb[256]; + int m_crg[256]; + int m_cbg[256]; + uint8* m_pScan_line_0; + uint8* m_pScan_line_1; + jpgd_status m_error_code; + int m_total_bytes_read; + + bool m_ready_flag; + bool m_eof_flag; + bool m_sample_buf_prev_valid; + bool m_has_sse2; + + inline int check_sample_buf_ofs(int ofs) const { assert(ofs >= 0); assert(ofs < m_max_blocks_per_row * 64); return ofs; } + void free_all_blocks(); + JPGD_NORETURN void stop_decoding(jpgd_status status); + void* alloc(size_t n, bool zero = false); + void* alloc_aligned(size_t nSize, uint32_t align = 16, bool zero = false); + void word_clear(void* p, uint16 c, uint n); + void prep_in_buffer(); + void read_dht_marker(); + void read_dqt_marker(); + void read_sof_marker(); + void skip_variable_marker(); + void read_dri_marker(); + void read_sos_marker(); + int next_marker(); + int process_markers(); + void locate_soi_marker(); + void locate_sof_marker(); + int locate_sos_marker(); + void init(jpeg_decoder_stream* pStream, uint32_t flags); + void create_look_ups(); + void fix_in_buffer(); + void transform_mcu(int mcu_row); + coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y); + inline jpgd_block_coeff_t* coeff_buf_getp(coeff_buf* cb, int block_x, int block_y); + void load_next_row(); + void decode_next_row(); + void make_huff_table(int index, huff_tables* pH); + void check_quant_tables(); + void check_huff_tables(); + bool calc_mcu_block_order(); + int init_scan(); + void init_frame(); + void process_restart(); + void decode_scan(pDecode_block_func decode_block_func); + void init_progressive(); + void init_sequential(); + void decode_start(); + void decode_init(jpeg_decoder_stream* pStream, uint32_t flags); + void H2V2Convert(); + uint32_t H2V2ConvertFiltered(); + void H2V1Convert(); + void H2V1ConvertFiltered(); + void H1V2Convert(); + void H1V2ConvertFiltered(); + void H1V1Convert(); + void gray_convert(); + void find_eoi(); + inline uint get_char(); + inline uint get_char(bool* pPadding_flag); + inline void stuff_char(uint8 q); + inline uint8 get_octet(); + inline uint get_bits(int num_bits); + inline uint get_bits_no_markers(int numbits); + inline int huff_decode(huff_tables* pH); + inline int huff_decode(huff_tables* pH, int& extrabits); + + // Clamps a value between 0-255. + static inline uint8 clamp(int i) + { + if (static_cast(i) > 255) + i = (((~i) >> 31) & 0xFF); + return static_cast(i); + } + int decode_next_mcu_row(); + + static void decode_block_dc_first(jpeg_decoder* pD, int component_id, int block_x, int block_y); + static void decode_block_dc_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y); + static void decode_block_ac_first(jpeg_decoder* pD, int component_id, int block_x, int block_y); + static void decode_block_ac_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y); + }; + +} // namespace jpgd + +#endif // JPEG_DECODER_H diff --git a/RichgelJpeg/license.txt b/RichgelJpeg/license.txt deleted file mode 100644 index 3f50d04..0000000 --- a/RichgelJpeg/license.txt +++ /dev/null @@ -1,506 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - - - diff --git a/RichgelJpeg/readme.txt b/RichgelJpeg/readme.txt deleted file mode 100644 index 6fe8c6b..0000000 --- a/RichgelJpeg/readme.txt +++ /dev/null @@ -1,240 +0,0 @@ -Small JPEG Decoder Library v0.93b -Dec. 28, 2001 -Copyright (C) 1994-2000 Rich Geldreich - -web: http://www.voicenet.com/~richgel -email: richgel@voicenet.com - ---- Introduction - -This C++ library decodes JPEG images. It's not the most full-featured -JPEG library available, but it's relatively fast, completely free (LGPL -license), uses little memory, and should be easy to understand and -further optimize (mostly because it's so small: the entire library is -only a few thousand lines long). The very common Huffman DCT-based -sequential and progressive modes of operation are supported. - -This library only handles JPEG decompression, upsampling, and colorspace -conversion. It does not handle pixel format conversion, quantization, -dithering, etc. - ---- Who's this library for? - -If your application's input set is limited in some way (say, you're -making a game or some other app that has prepared resources), this -library may suite your needs. - -This library may also prove useful to those that want to read JPEG -images on very small 32-bit platforms or embedded devices. See the -porting section, below. (This code has been successfully ported to work -on SH3, ARM, and MIPS CPU's.) - -I do not recommend using this library in a product that requires -extremely high image quality or is going to be reading many arbitrary -images supplied by the user, unless you know exactly what you're doing. -The library does not support the more rare sampling factors/colorspaces, -and only uses a box filter to upsample the chrominance components. - -I have tested this particular implementation with over 175 megabytes of -JPEG images from a variety of sources. Still, this is not a trivial -piece of software, so please e-mail me if you find any bugs. - ---- Alternatives - -Intel has a free JPEG Library that is also quite fast, but they don't -distribute the source: - -http://developer.intel.com/vtune/PERFLIBST/ijl/index.htm - -If you are creating a product that requires the highest quality and most -compatibility I recommend using the Independent JPEG Group's free -library (includes source): - -http://www.ijg.org - ---- Features - -Simple (very little code, especially when compared to other JPEG libraries) - -Free (LGPL license) - -A lot of optional MMX specific optimizations: - IDCT (using Intel's free MMX IDCT module) - Merged H2V2 upsampler/YCbCr->RGB conversion - Fast "getbits" - -Supports the most common (widely used) image types: - Grayscale - YCbCr colorspace: H1V1, H1V2, H2V1, or H2V2 sampling factors - -Progressive images - ---- Instructions - -Make sure you have Visual C++ 6.0 Service Pack 3 or higher. - -Load the workspace file, located at jpgd/jpgd.dsw. The example console -mode program, jpg2tga, requires two parameters for it to do anything: a -source filename (a valid JPEG image), and a destination filename (TGA). -Example: - -jpg2tga input.jpg output.tga - -The image input.jpg will be written to ouput.tga. You may then view -output.tga to verify that everything worked as expected. - -There are a number of useful test images in the "test_images" folder -that can be used to help verify that the decoder is working properly. - -Notes: I hardcoded the "use_mmx" parameter to true in the jpeg_decoder -constructor call.. If you don't have an MMX capable processor you will -need to change this code. (A production program should check if the -processor supports MMX at run-time and adjust this parameter -accordingly.) - -You should be able to compile and link using VC++ 5.0 if you remake the -projects/workspace. - ---- Decoder Streams - -To decode JPEG streams straight from memory, or from some other source, -study the jpeg_decoder_stream class which is defined in jpegdecoder.h. -All data input is handled through an object which has this interface as -its base class. - -An example decoder stream class that reads JPEG files from standard FILE -streams is included (see jpeg_decoder_file_stream). The jpg2tga example -program uses this decoder stream class. - ---- Porting - -I've modified the library so it's much easier to selectively remove the -inline x86 assembler and MMX specific code. See the following macros in -jpegdecoder.h: - -#define SUPPORT_X86ASM -#define SUPPORT_MMX - ---- Intel C/C++ Compiler Notes: - -To use the Intel C/C++ Compiler (v4.0 or higher): Make sure the "Intel -C/C++ Compiler" checkbox is checked in the "Select Compiler" tool. If -it's not, the h2v2.cpp module will not include the MMX implementation. - -The h2v2.obj module in the included libs was compiled with the Intel -Compiler-- I hope this causes no trouble for those that don't have this -product. It shouldn't, but if it does, just recompile. - -For some reason, the get_bits_2_mmx() method isn't inlined properly -by ICC, causing a crash in Release builds. This is why all modules -except h2v2.cpp have the _USE_NON_INTEL_COMPILER symbol defined. For -now, if you must use ICC to compile the library, either disable inlining -or don't define the SUPPORT_MMX symbol (jpgdecoder.h). - ---- Partial Update History -v.93a: - -Fixed dumb bug in the decode_next_row functions that could cause bogus non-zero -coefficients from leaking through in rare cases. - -v.93: - -prep_in_buffer() now saves/restores the MMX state before the -jpeg_decoder_stream's read() method is called. - -Moved a lot of the inline asm/MMX code to jpegdecoder.inl to simplify -the main header file. - -Added the SUPPORT_X86ASM and SUPPORT_MMX defines, to ease porting to -non-x86 platforms (see the top of jpegdecoder.h). - -v.92: - -Removed Intel's old MMX IDCT module, replaced with a newer, free module -from their web site that was specifically designed for JPEG. I have -detected no overflow problems with this IDCT. - -Rewrote the MMX intrinsic code in the h2v2.cpp module. Should -be faster and more accurate now. - -Added MMX specific getbits()/Huffman decoding methods. Coefficient -decoding is the main bottleneck (approximately 50%!) when MMX is enabled -so it must be done quickly. - -Changed main decoder so it does not clear the entire coefficient buffer -every row. This was really slowing the entire decoder down! - -Changed merged upsampling/colorspace conversion methods to write the -destination pixels to a different buffer. Also changed the RGB output -format from 3 bytes/pixel to 4 bytes/pixel (more efficient for MMX code -to write). - ---- History - -Some years ago, a friend (Matt Pritchard, now with Ensemble -Studios) and I wrote a 16-bit real mode DOS image viewer named "PowerView" -(PV). Matt convinced me that we needed to add JPEG support -- no small feat, -especially considering that at the time (1994) JPEG was still rather new. - -The Independent JPEG Group's (www.ijg.org) library was definitely an -option, but its sheer bulk seemed like it would have broken PV. (PV's -memory situation was bleak: less than ~500k for all code/near -and far data. It supported EMS/XMS, but only for special cases. Things -got so bad that I had to use Borland's run-time code swapping/paging -system to free up low RAM. Modifying the IJG code to handle this -reliably seemed like much more trouble than it was worth.) Also, -incorporating so much of someone else's code was sure to make the -program less reliable, overall. We also wanted to stand out from the -crowd, so I decided to create our own implementation. - -Approximately one week later, the baseline decoder was working. The -upsampling/colorspace conversion code, Huffman decoder, and IDCT modules -where written entirely in real-mode assembler. The IDCT module -performed no multiplies, just lots of overlapped/pipelined, 32-bit adds -from EMS memory lookup tables. (Each 32-bit add summed two individual -16-bit quantities.) It also employed an interesting "fast path" -optimization: using macros, an individual IDCT was created for each -possible input case because many AC coefficients are 0 after -quantization. (I will probably port this IDCT to 32-bit code and -release it soon. It performs a lot of table lookups to a 64k buffer, so -I wonder how well it will perform on today's machines.) - -Much later on, after the web became very popular, I added support for -progressive images. - -A short time after, I wrote a rather complete JPEG encoder from scratch. -This code will be much easier to port because I wrote it keeping -portability in mind. I'm probably going to release this code within the -next few months. - ---- Future Changes - -Partial list: - -I would like to replace the IJG's integer IDCT module (named IDCT.CPP in -this lib) with something else, because it's copyrighted by Thomas G. -Lane of the IJG. I am not sure if including this small bit of code -requires the user to include the usual "Parts of this code where written -by the IJG...", etc. statement in their product documentation or "About" -dialog. - -Possibly add AMD 3D-Now or P3 specific modules. - -Add bilinear filtering to the upsampler/colorspace conversion code. -Right now, only a simple box filter is implemented, which can sometimes -cause noticeable artifacts. - -It would be interesting to see how practical it is to use Direct3D for -upsampling and colorspace conversion. Upsampling could be done by using -SetRenderTarget() with filtered texture mapping, and various -blending operations for colorspace conversion. I'm almost positive this -is doable, but I'm not sure if 8-bits per component is really enough. - ---- License - -Except for those modules which are copyrighted by others, this library -is covered under the LGPL license. Please see license.txt. - -idct.cpp is from the IJG. It's copyrighted by Thomas G. Lane. Please -see the top of this file for more information. - diff --git a/TWiki/TWRenderTable.cpp b/TWiki/TWRenderTable.cpp index 3c194c8..bf0b408 100644 --- a/TWiki/TWRenderTable.cpp +++ b/TWiki/TWRenderTable.cpp @@ -825,6 +825,9 @@ int TWRenderTable::levelForBorderStyle(TWHTMLStyleBorderStyle style){ case TWHTMLStyleBorderStyleNone: return -1; } + + // Not reached. + return 0; } /** determines which border takes precedence. diff --git a/TWiki/TWUtils.cpp b/TWiki/TWUtils.cpp index 0163b7d..34bfa71 100644 --- a/TWiki/TWUtils.cpp +++ b/TWiki/TWUtils.cpp @@ -164,7 +164,7 @@ std::wstring TWUtils::stringWithIntValue(int iv){ return g_positives[iv]; }else if(iv>=-9 && iv<=-1){ return g_positives[-1-iv]; - }else if(iv==-2147483648) + }else if(iv==-2147483647-1) // we have to filter this case because // if this value was negated, result is unknown. return g_minIntString; diff --git a/XTBJpegLoader.cpp b/XTBJpegLoader.cpp index 336c9bd..82f2a43 100644 --- a/XTBJpegLoader.cpp +++ b/XTBJpegLoader.cpp @@ -26,7 +26,7 @@ bool XTBJpegLoader::probe(XTBStream *steam){ XTBJpegLoader::XTBJpegLoader(XTBStream *stream): m_stream(stream){ m_stream2=new XTBRichgelJpegStream(m_stream); - m_decoder=new jpeg_decoder(m_stream2, false); + m_decoder=new jpgd::jpeg_decoder(m_stream2, false); if(m_decoder->get_error_code()){ int errorCode=m_decoder->get_error_code(); delete m_decoder; @@ -46,7 +46,7 @@ XTBJpegLoader::~XTBJpegLoader(){ } twDC *XTBJpegLoader::image(){ - if(m_decoder->begin()){ + if(m_decoder->begin_decoding()){ int errorCode=m_decoder->get_error_code(); delete m_decoder; delete m_stream2; @@ -58,7 +58,7 @@ twDC *XTBJpegLoader::image(){ uint8_t *lineBuffer; // don't need to malloc/free twSDLDC *image; SDL_Surface *surf; - uint lineLen; + jpgd::uint lineLen; int width=m_decoder->get_width(); @@ -72,7 +72,7 @@ twDC *XTBJpegLoader::image(){ assert(surf->format->BitsPerPixel==16); int y=0; - while(!m_decoder->decode((void **)&lineBuffer, &lineLen)){ + while(!m_decoder->decode((const void **)&lineBuffer, &lineLen)){ if(m_decoder->get_num_components()==1){ convert8To565(dest, lineBuffer, m_decoder->get_width(), y); diff --git a/XTBJpegLoader.h b/XTBJpegLoader.h index 24f4379..300b9be 100644 --- a/XTBJpegLoader.h +++ b/XTBJpegLoader.h @@ -9,14 +9,14 @@ #pragma once #include "XTBStream.h" +#include "XTBRichgelJpegStream.h" -class jpeg_decoder; class XTBRichgelJpegStream; class XTBJpegLoader{ XTBStream *m_stream; XTBRichgelJpegStream *m_stream2; - jpeg_decoder *m_decoder; + jpgd::jpeg_decoder *m_decoder; void convert888To565(uint16_t *dest, const uint8_t *src, diff --git a/XTBRichgelJpegStream.cpp b/XTBRichgelJpegStream.cpp index e957ba3..7b4c9b4 100644 --- a/XTBRichgelJpegStream.cpp +++ b/XTBRichgelJpegStream.cpp @@ -13,7 +13,7 @@ m_stream(stream){} XTBRichgelJpegStream::~XTBRichgelJpegStream(){} -int XTBRichgelJpegStream::read(uchar *Pbuf, int max_bytes_to_read, +int XTBRichgelJpegStream::read(jpgd::uint8 *Pbuf, int max_bytes_to_read, bool *Peof_flag){ size_t readBytes; readBytes=m_stream->readToBuffer(Pbuf, max_bytes_to_read); diff --git a/XTBRichgelJpegStream.h b/XTBRichgelJpegStream.h index 5c4bf3c..e0e9eaf 100644 --- a/XTBRichgelJpegStream.h +++ b/XTBRichgelJpegStream.h @@ -8,15 +8,15 @@ #pragma once -#include "RichgelJpeg/jpegdecoder.h" +#include "RichgelJpeg/jpgd.h" #include "XTBStream.h" -class XTBRichgelJpegStream: public jpeg_decoder_stream{ +class XTBRichgelJpegStream: public jpgd::jpeg_decoder_stream{ XTBStream *m_stream; public: XTBRichgelJpegStream(XTBStream *); virtual ~XTBRichgelJpegStream(); - virtual int read(uchar *Pbuf, int max_bytes_to_read, bool *Peof_flag); + virtual int read(jpgd::uint8 *Pbuf, int max_bytes_to_read, bool *Peof_flag); }; diff --git a/XTBook-en.png b/XTBook-en.png new file mode 100644 index 0000000..21a3c6f Binary files /dev/null and b/XTBook-en.png differ diff --git a/XTBook-ja.png b/XTBook-ja.png new file mode 100644 index 0000000..7cfe488 Binary files /dev/null and b/XTBook-ja.png differ diff --git a/XZEmbedded/xz.h b/XZEmbedded/xz.h index 810cb10..d24b94a 100644 --- a/XZEmbedded/xz.h +++ b/XZEmbedded/xz.h @@ -2,7 +2,7 @@ * XZ decompressor * * Authors: Lasse Collin - * Igor Pavlov + * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. @@ -32,7 +32,7 @@ extern "C" { * enum xz_mode - Operation mode * * @XZ_SINGLE: Single-call mode. This uses less RAM than - * than multi-call modes, because the LZMA2 + * multi-call modes, because the LZMA2 * dictionary doesn't need to be allocated as * part of the decoder state. All required data * structures are allocated at initialization, @@ -251,6 +251,22 @@ XZ_EXTERN void xz_dec_end(struct xz_dec *s); # endif #endif +/* + * If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64 + * implementation is needed too. + */ +#ifndef XZ_USE_CRC64 +# undef XZ_INTERNAL_CRC64 +# define XZ_INTERNAL_CRC64 0 +#endif +#ifndef XZ_INTERNAL_CRC64 +# ifdef __KERNEL__ +# error Using CRC64 in the kernel has not been implemented. +# else +# define XZ_INTERNAL_CRC64 1 +# endif +#endif + #if XZ_INTERNAL_CRC32 /* * This must be called before any other xz_* function to initialize @@ -266,6 +282,21 @@ XZ_EXTERN void xz_crc32_init(void); XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc); #endif +#if XZ_INTERNAL_CRC64 +/* + * This must be called before any other xz_* function (except xz_crc32_init()) + * to initialize the CRC64 lookup table. + */ +XZ_EXTERN void xz_crc64_init(void); + +/* + * Update CRC64 value using the polynomial from ECMA-182. To start a new + * calculation, the third argument must be zero. To continue the calculation, + * the previously returned value is passed as the third argument. + */ +XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc); +#endif + #ifdef __cplusplus } #endif diff --git a/XZEmbedded/xz.txt b/XZEmbedded/xz.txt new file mode 100644 index 0000000..1e1a915 --- /dev/null +++ b/XZEmbedded/xz.txt @@ -0,0 +1,122 @@ + +XZ data compression in Linux +============================ + +Introduction + + XZ is a general purpose data compression format with high compression + ratio and relatively fast decompression. The primary compression + algorithm (filter) is LZMA2. Additional filters can be used to improve + compression ratio even further. E.g. Branch/Call/Jump (BCJ) filters + improve compression ratio of executable data. + + The XZ decompressor in Linux is called XZ Embedded. It supports + the LZMA2 filter and optionally also BCJ filters. CRC32 is supported + for integrity checking. The home page of XZ Embedded is at + , where you can find the + latest version and also information about using the code outside + the Linux kernel. + + For userspace, XZ Utils provide a zlib-like compression library + and a gzip-like command line tool. XZ Utils can be downloaded from + . + +XZ related components in the kernel + + The xz_dec module provides XZ decompressor with single-call (buffer + to buffer) and multi-call (stateful) APIs. The usage of the xz_dec + module is documented in include/linux/xz.h. + + The xz_dec_test module is for testing xz_dec. xz_dec_test is not + useful unless you are hacking the XZ decompressor. xz_dec_test + allocates a char device major dynamically to which one can write + .xz files from userspace. The decompressed output is thrown away. + Keep an eye on dmesg to see diagnostics printed by xz_dec_test. + See the xz_dec_test source code for the details. + + For decompressing the kernel image, initramfs, and initrd, there + is a wrapper function in lib/decompress_unxz.c. Its API is the + same as in other decompress_*.c files, which is defined in + include/linux/decompress/generic.h. + + scripts/xz_wrap.sh is a wrapper for the xz command line tool found + from XZ Utils. The wrapper sets compression options to values suitable + for compressing the kernel image. + + For kernel makefiles, two commands are provided for use with + $(call if_needed). The kernel image should be compressed with + $(call if_needed,xzkern) which will use a BCJ filter and a big LZMA2 + dictionary. It will also append a four-byte trailer containing the + uncompressed size of the file, which is needed by the boot code. + Other things should be compressed with $(call if_needed,xzmisc) + which will use no BCJ filter and 1 MiB LZMA2 dictionary. + +Notes on compression options + + Since the XZ Embedded supports only streams with no integrity check or + CRC32, make sure that you don't use some other integrity check type + when encoding files that are supposed to be decoded by the kernel. With + liblzma, you need to use either LZMA_CHECK_NONE or LZMA_CHECK_CRC32 + when encoding. With the xz command line tool, use --check=none or + --check=crc32. + + Using CRC32 is strongly recommended unless there is some other layer + which will verify the integrity of the uncompressed data anyway. + Double checking the integrity would probably be waste of CPU cycles. + Note that the headers will always have a CRC32 which will be validated + by the decoder; you can only change the integrity check type (or + disable it) for the actual uncompressed data. + + In userspace, LZMA2 is typically used with dictionary sizes of several + megabytes. The decoder needs to have the dictionary in RAM, thus big + dictionaries cannot be used for files that are intended to be decoded + by the kernel. 1 MiB is probably the maximum reasonable dictionary + size for in-kernel use (maybe more is OK for initramfs). The presets + in XZ Utils may not be optimal when creating files for the kernel, + so don't hesitate to use custom settings. Example: + + xz --check=crc32 --lzma2=dict=512KiB inputfile + + An exception to above dictionary size limitation is when the decoder + is used in single-call mode. Decompressing the kernel itself is an + example of this situation. In single-call mode, the memory usage + doesn't depend on the dictionary size, and it is perfectly fine to + use a big dictionary: for maximum compression, the dictionary should + be at least as big as the uncompressed data itself. + +Future plans + + Creating a limited XZ encoder may be considered if people think it is + useful. LZMA2 is slower to compress than e.g. Deflate or LZO even at + the fastest settings, so it isn't clear if LZMA2 encoder is wanted + into the kernel. + + Support for limited random-access reading is planned for the + decompression code. I don't know if it could have any use in the + kernel, but I know that it would be useful in some embedded projects + outside the Linux kernel. + +Conformance to the .xz file format specification + + There are a couple of corner cases where things have been simplified + at expense of detecting errors as early as possible. These should not + matter in practice all, since they don't cause security issues. But + it is good to know this if testing the code e.g. with the test files + from XZ Utils. + +Reporting bugs + + Before reporting a bug, please check that it's not fixed already + at upstream. See to get the + latest code. + + Report bugs to or visit #tukaani on + Freenode and talk to Larhzu. I don't actively read LKML or other + kernel-related mailing lists, so if there's something I should know, + you should email to me personally or use IRC. + + Don't bother Igor Pavlov with questions about the XZ implementation + in the kernel or about XZ Utils. While these two implementations + include essential code that is directly based on Igor Pavlov's code, + these implementations aren't maintained nor supported by him. + diff --git a/XZEmbedded/xz_config.h b/XZEmbedded/xz_config.h index a265f88..eb9dac1 100644 --- a/XZEmbedded/xz_config.h +++ b/XZEmbedded/xz_config.h @@ -10,6 +10,9 @@ #ifndef XZ_CONFIG_H #define XZ_CONFIG_H +/* Uncomment to enable CRC64 support. */ +/* #define XZ_USE_CRC64 */ + /* Uncomment as needed to enable BCJ filter decoders. */ /* #define XZ_DEC_X86 */ /* #define XZ_DEC_POWERPC */ @@ -18,10 +21,21 @@ /* #define XZ_DEC_ARMTHUMB */ /* #define XZ_DEC_SPARC */ -#include +/* + * MSVC doesn't support modern C but XZ Embedded is mostly C89 + * so these are enough. + */ +#ifdef _MSC_VER +typedef unsigned char bool; +# define true 1 +# define false 0 +# define inline __inline +#else +# include +#endif + #include #include -#include #include "xz.h" diff --git a/XZEmbedded/xz_crc32.c b/XZEmbedded/xz_crc32.c index 34532d1..5627b00 100644 --- a/XZEmbedded/xz_crc32.c +++ b/XZEmbedded/xz_crc32.c @@ -2,7 +2,7 @@ * CRC32 using the polynomial from IEEE-802.3 * * Authors: Lasse Collin - * Igor Pavlov + * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. diff --git a/XZEmbedded/xz_dec_lzma2.c b/XZEmbedded/xz_dec_lzma2.c index a6cdc96..2deb544 100644 --- a/XZEmbedded/xz_dec_lzma2.c +++ b/XZEmbedded/xz_dec_lzma2.c @@ -2,7 +2,7 @@ * LZMA2 decoder * * Authors: Lasse Collin - * Igor Pavlov + * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. @@ -387,7 +387,14 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, *left -= copy_size; - memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + /* + * If doing in-place decompression in single-call mode and the + * uncompressed size of the file is larger than the caller + * thought (i.e. it is invalid input!), the buffers below may + * overlap and cause undefined behavior with memcpy(). + * With valid inputs memcpy() would be fine here. + */ + memmove(dict->buf + dict->pos, b->in + b->in_pos, copy_size); dict->pos += copy_size; if (dict->full < dict->pos) @@ -397,7 +404,11 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, if (dict->pos == dict->end) dict->pos = 0; - memcpy(b->out + b->out_pos, b->in + b->in_pos, + /* + * Like above but for multi-call mode: use memmove() + * to avoid undefined behavior with invalid input. + */ + memmove(b->out + b->out_pos, b->in + b->in_pos, copy_size); } @@ -421,6 +432,12 @@ static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) if (dict->pos == dict->end) dict->pos = 0; + /* + * These buffers cannot overlap even if doing in-place + * decompression because in multi-call mode dict->buf + * has been allocated by us in this file; it's not + * provided by the caller like in single-call mode. + */ memcpy(b->out + b->out_pos, dict->buf + dict->start, copy_size); } @@ -1043,6 +1060,8 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, s->lzma2.sequence = SEQ_LZMA_PREPARE; + /* Fall through */ + case SEQ_LZMA_PREPARE: if (s->lzma2.compressed < RC_INIT_BYTES) return XZ_DATA_ERROR; @@ -1053,6 +1072,8 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, s->lzma2.compressed -= RC_INIT_BYTES; s->lzma2.sequence = SEQ_LZMA_RUN; + /* Fall through */ + case SEQ_LZMA_RUN: /* * Set dictionary limit to indicate how much we want @@ -1142,6 +1163,7 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props) if (DEC_IS_DYNALLOC(s->dict.mode)) { if (s->dict.allocated < s->dict.size) { + s->dict.allocated = s->dict.size; vfree(s->dict.buf); s->dict.buf = vmalloc(s->dict.size); if (s->dict.buf == NULL) { diff --git a/XZEmbedded/xz_dec_stream.c b/XZEmbedded/xz_dec_stream.c index ac809b1..f69581b 100644 --- a/XZEmbedded/xz_dec_stream.c +++ b/XZEmbedded/xz_dec_stream.c @@ -10,6 +10,12 @@ #include "xz_private.h" #include "xz_stream.h" +#ifdef XZ_USE_CRC64 +# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64) +#else +# define IS_CRC64(check_type) false +#endif + /* Hash used to validate the Index field */ struct xz_dec_hash { vli_type unpadded; @@ -42,8 +48,13 @@ struct xz_dec { size_t in_start; size_t out_start; +#ifdef XZ_USE_CRC64 + /* CRC32 or CRC64 value in Block or CRC32 value in Index */ + uint64_t crc; +#else /* CRC32 value in Block or Index */ - uint32_t crc32; + uint32_t crc; +#endif /* Type of the integrity check calculated from uncompressed data */ enum xz_check check_type; @@ -208,8 +219,8 @@ static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in, * the observed compressed and uncompressed sizes of the Block so that * they don't exceed the values possibly stored in the Block Header * (validation assumes that no integer overflow occurs, since vli_type - * is normally uint64_t). Update the CRC32 if presence of the CRC32 - * field was indicated in Stream Header. + * is normally uint64_t). Update the CRC32 or CRC64 value if presence of + * the CRC32 or CRC64 field was indicated in Stream Header. * * Once the decoding is finished, validate that the observed sizes match * the sizes possibly stored in the Block Header. Update the hash and @@ -242,8 +253,13 @@ static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) return XZ_DATA_ERROR; if (s->check_type == XZ_CHECK_CRC32) - s->crc32 = xz_crc32(b->out + s->out_start, - b->out_pos - s->out_start, s->crc32); + s->crc = xz_crc32(b->out + s->out_start, + b->out_pos - s->out_start, s->crc); +#ifdef XZ_USE_CRC64 + else if (s->check_type == XZ_CHECK_CRC64) + s->crc = xz_crc64(b->out + s->out_start, + b->out_pos - s->out_start, s->crc); +#endif if (ret == XZ_STREAM_END) { if (s->block_header.compressed != VLI_UNKNOWN @@ -264,6 +280,8 @@ static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) #else if (s->check_type == XZ_CHECK_CRC32) s->block.hash.unpadded += 4; + else if (IS_CRC64(s->check_type)) + s->block.hash.unpadded += 8; #endif s->block.hash.uncompressed += s->block.uncompressed; @@ -282,7 +300,7 @@ static void index_update(struct xz_dec *s, const struct xz_buf *b) { size_t in_used = b->in_pos - s->in_start; s->index.size += in_used; - s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); + s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc); } /* @@ -340,23 +358,25 @@ static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) } /* - * Validate that the next four input bytes match the value of s->crc32. - * s->pos must be zero when starting to validate the first byte. + * Validate that the next four or eight input bytes match the value + * of s->crc. s->pos must be zero when starting to validate the first byte. + * The "bits" argument allows using the same code for both CRC32 and CRC64. */ -static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b) +static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b, + uint32_t bits) { do { if (b->in_pos == b->in_size) return XZ_OK; - if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) + if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++]) return XZ_DATA_ERROR; s->pos += 8; - } while (s->pos < 32); + } while (s->pos < bits); - s->crc32 = 0; + s->crc = 0; s->pos = 0; return XZ_STREAM_END; @@ -397,10 +417,11 @@ static enum xz_ret dec_stream_header(struct xz_dec *s) return XZ_OPTIONS_ERROR; /* - * Of integrity checks, we support only none (Check ID = 0) and - * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, - * we will accept other check types too, but then the check won't - * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. + * Of integrity checks, we support none (Check ID = 0), + * CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4). + * However, if XZ_DEC_ANY_CHECK is defined, we will accept other + * check types too, but then the check won't be verified and + * a warning (XZ_UNSUPPORTED_CHECK) will be given. */ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; @@ -408,10 +429,10 @@ static enum xz_ret dec_stream_header(struct xz_dec *s) if (s->check_type > XZ_CHECK_MAX) return XZ_OPTIONS_ERROR; - if (s->check_type > XZ_CHECK_CRC32) + if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type)) return XZ_UNSUPPORTED_CHECK; #else - if (s->check_type > XZ_CHECK_CRC32) + if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type)) return XZ_OPTIONS_ERROR; #endif @@ -583,6 +604,8 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) if (ret != XZ_OK) return ret; + /* Fall through */ + case SEQ_BLOCK_START: /* We need one byte of input to continue. */ if (b->in_pos == b->in_size) @@ -606,6 +629,8 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) s->temp.pos = 0; s->sequence = SEQ_BLOCK_HEADER; + /* Fall through */ + case SEQ_BLOCK_HEADER: if (!fill_temp(s, b)) return XZ_OK; @@ -616,6 +641,8 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_BLOCK_UNCOMPRESS; + /* Fall through */ + case SEQ_BLOCK_UNCOMPRESS: ret = dec_block(s, b); if (ret != XZ_STREAM_END) @@ -623,6 +650,8 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_BLOCK_PADDING; + /* Fall through */ + case SEQ_BLOCK_PADDING: /* * Size of Compressed Data + Block Padding @@ -643,9 +672,16 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_BLOCK_CHECK; + /* Fall through */ + case SEQ_BLOCK_CHECK: if (s->check_type == XZ_CHECK_CRC32) { - ret = crc32_validate(s, b); + ret = crc_validate(s, b, 32); + if (ret != XZ_STREAM_END) + return ret; + } + else if (IS_CRC64(s->check_type)) { + ret = crc_validate(s, b, 64); if (ret != XZ_STREAM_END) return ret; } @@ -665,6 +701,8 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_INDEX_PADDING; + /* Fall through */ + case SEQ_INDEX_PADDING: while ((s->index.size + (b->in_pos - s->in_start)) & 3) { @@ -687,14 +725,18 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_INDEX_CRC32; + /* Fall through */ + case SEQ_INDEX_CRC32: - ret = crc32_validate(s, b); + ret = crc_validate(s, b, 32); if (ret != XZ_STREAM_END) return ret; s->temp.size = STREAM_HEADER_SIZE; s->sequence = SEQ_STREAM_FOOTER; + /* Fall through */ + case SEQ_STREAM_FOOTER: if (!fill_temp(s, b)) return XZ_OK; @@ -802,7 +844,7 @@ XZ_EXTERN void xz_dec_reset(struct xz_dec *s) s->sequence = SEQ_STREAM_HEADER; s->allow_buf_error = false; s->pos = 0; - s->crc32 = 0; + s->crc = 0; memzero(&s->block, sizeof(s->block)); memzero(&s->index, sizeof(s->index)); s->temp.pos = 0; diff --git a/XZEmbedded/xz_lzma2.h b/XZEmbedded/xz_lzma2.h index 071d67b..92d852d 100644 --- a/XZEmbedded/xz_lzma2.h +++ b/XZEmbedded/xz_lzma2.h @@ -2,7 +2,7 @@ * LZMA2 definitions * * Authors: Lasse Collin - * Igor Pavlov + * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. diff --git a/XZEmbedded/xz_private.h b/XZEmbedded/xz_private.h index a65633e..482b90f 100644 --- a/XZEmbedded/xz_private.h +++ b/XZEmbedded/xz_private.h @@ -12,7 +12,7 @@ #ifdef __KERNEL__ # include -# include +# include # include /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ # ifndef XZ_PREBOOT diff --git a/XZEmbedded/xz_stream.h b/XZEmbedded/xz_stream.h index 66cb5a7..430bb3a 100644 --- a/XZEmbedded/xz_stream.h +++ b/XZEmbedded/xz_stream.h @@ -19,7 +19,7 @@ /* * See the .xz file format specification at - * http://tukaani.org/xz/xz-file-format.txt + * https://tukaani.org/xz/xz-file-format.txt * to understand the container format. */ diff --git a/build.cegcc/Makefile b/build.cegcc/Makefile index f0e3cde..f5c65e0 100644 --- a/build.cegcc/Makefile +++ b/build.cegcc/Makefile @@ -1,4 +1,4 @@ -SDL=/mnt/c/Users/watamario15/Documents/wata/Git/SDL-1.2/build-wince/.libs +SDL=/mnt/c/Users/watamario15/Documents/wata/Git/SDL-1.2/build.cegcc/.libs SDLINCLUDE=/mnt/c/Users/watamario15/Documents/wata/Git/SDL-1.2/include CEGCC=/opt/cegcc CC=$(CEGCC)/bin/arm-mingw32ce-gcc @@ -6,11 +6,11 @@ CXX=$(CEGCC)/bin/arm-mingw32ce-g++ LD=$(CEGCC)/bin/arm-mingw32ce-g++ STRIP=$(CEGCC)/bin/arm-mingw32ce-strip WINDRES=$(CEGCC)/bin/arm-mingw32ce-windres -CCFLAGS= -I$(SRCPATH)/tcw/include -I$(SRCPATH) -I$(SDLINCLUDE) -DEV_PLATFORM_WIN32 -DUNICODE -D_UNICODE -DEV_UNSAFE_SWPRINTF -mwin32 -Os -mcpu=arm926ej-s -D_WIN32_WCE=0x500 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DNDEBUG +CCFLAGS= -I$(SRCPATH)/tcw/include -I$(SRCPATH) -I$(SDLINCLUDE) -DEV_PLATFORM_WIN32 -DUNICODE -D_UNICODE -DEV_UNSAFE_SWPRINTF -mwin32 -O3 -mcpu=arm926ej-s -D_WIN32_WCE=0x500 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DNDEBUG CXXFLAGS=$(CCFLAGS) --std=gnu++03 LDFLAGS=-L$(SDL) -lSDLmain -lSDL -lmmtimer -mwin32 -mthreads -static -TARGET=AppMain.exe -PACKAGE=build +TARGET=AppMain_.exe +PACKAGE=XTBook-0.2.7-Brain .PHONY: all clean @@ -29,9 +29,11 @@ $(TARGET): $(OBJS) packaging: $(TARGET) mkdir -p $(PACKAGE) touch $(PACKAGE)/index.din + touch $(PACKAGE)/AppMain.cfg + wget https://cdn.discordapp.com/attachments/767337494513188894/980165000758972487/exeopener.exe -O $(PACKAGE)/AppMain.exe $(STRIP) $(CEGCC)/arm-mingw32ce/bin/mingwm10.dll -o $(PACKAGE)/mingwm10.dll cp $(TARGET) $(PACKAGE) - cp -r ../StartupItems $(PACKAGE) + mkdir -p $(PACKAGE)/StartupItems cp -r ../Languages $(PACKAGE) cp -r ../InternalDictionaries $(PACKAGE) cp -r ../Help $(PACKAGE) diff --git a/build.cegcc/Makefile.i b/build.cegcc/Makefile.i index 52d45a8..d66c48b 100644 --- a/build.cegcc/Makefile.i +++ b/build.cegcc/Makefile.i @@ -480,19 +480,15 @@ tinyxmlerror.o: ../TinyXML/tinyxmlerror.cpp XTBook_Prefix.pch.gch $(CXX) -include XTBook_Prefix.pch -c ../TinyXML/tinyxmlerror.cpp -o tinyxmlerror.o $(CFLAGS) $(CXXFLAGS) -I.. tinyxmlparser.o: ../TinyXML/tinyxmlparser.cpp XTBook_Prefix.pch.gch $(CXX) -include XTBook_Prefix.pch -c ../TinyXML/tinyxmlparser.cpp -o tinyxmlparser.o $(CFLAGS) $(CXXFLAGS) -I.. -H2v2.o: ../RichgelJpeg/H2v2.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/H2v2.cpp -o H2v2.o $(CFLAGS) $(CXXFLAGS) -I.. -idct.o: ../RichgelJpeg/idct.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/idct.cpp -o idct.o $(CFLAGS) $(CXXFLAGS) -I.. -jpegdecoder.o: ../RichgelJpeg/jpegdecoder.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/jpegdecoder.cpp -o jpegdecoder.o $(CFLAGS) $(CXXFLAGS) -I.. +jpgd.o: ../RichgelJpeg/jpgd.cpp XTBook_Prefix.pch.gch + $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/jpgd.cpp -o jpgd.o $(CFLAGS) $(CXXFLAGS) -DJPGD_USE_SSE2=0 -I.. xz_crc32.o: ../XZEmbedded/xz_crc32.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_crc32.c -o xz_crc32.o $(CFLAGS) xz_dec_lzma2.o: ../XZEmbedded/xz_dec_lzma2.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_dec_lzma2.c -o xz_dec_lzma2.o $(CFLAGS) xz_dec_stream.o: ../XZEmbedded/xz_dec_stream.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_dec_stream.c -o xz_dec_stream.o $(CFLAGS) -resource.o: ../xtbook.rc - $(WINDRES) ../xtbook.rc resource.o -OBJS= TWRenderDCTcw.o TWRenderManagerTcw.o TWViewer.o TWViewerImageManager.o XTBAboutDialog.o XTBActionMenuItem.o XTBArticle.o XTBBrowser.o XTBButtonMenuItem.o XTBContentsChooser.o XTBContentsDataSource.o XTBCoreDictionaryTypeRegister.o XTBDialogSheet.o XTBDicDBMemoryCache.o XTBDicDBReader.o XTBDictionary.o XTBDictionaryIterator.o XTBDictionaryType.o XTBDocument.o XTBDrawTest.o XTBEventManager.o XTBException.o XTBFileStream.o XTBFont.o XTBFont1Bit.o XTBFont4Bit.o XTBFootnoteView.o XTBHGGothic.o XTBHGGothicAA.o XTBHistory.o XTBImage.o XTBImageArticle.o XTBImageComplex.o XTBImageComplexArticle.o XTBImageComplexDictionary.o XTBImageComplexIterator.o XTBImageLoader.o XTBIndexDBReader.o XTBJpegLoader.o XTBLabelMenuItem.o XTBListView.o XTBListViewDataSource.o XTBListViewTest.o XTBMainWindow.o XTBMemoryStream.o XTBMenu.o XTBMenuItem.o XTBNotificationCenter.o XTBOverlay.o XTBPlainArticle.o XTBPreferenceLocaleDataSource.o XTBPreferenceWindow.o XTBProgressOverlay.o XTBRaxDecompressor.o XTBRichgelJpegStream.o XTBRomajiTable.o XTBRootPanel.o XTBRootWindow.o XTBSampleDictionary.o XTBSampleDictionaryArticle.o XTBSampleDictionaryImageArticle.o XTBSampleDictionaryIterator.o XTBSampleDictionaryType.o XTBScrollView.o XTBScrollViewTest.o XTBSearchBar.o XTBSearchErrorView.o XTBSearchView.o XTBSearchViewDataSource.o XTBSeparatorMenuItem.o XTBSkin.o XTBSoftKeyboard.o XTBStartPageBookmarkDataSource.o XTBStartPageHistoryDataSource.o XTBStartPageList.o XTBStartPageListDataSource.o XTBStartPageView.o XTBStream.o XTBStringTable.o XTBStringTableFileHandle.o XTBTabBar.o XTBTabPage.o XTBTestWindow.o XTBTextBox.o XTBTextField.o XTBTextFieldTest.o XTBURL.o XTBUserDefaults.o XTBViewer.o XTBViewerTest.o XTBWikiplexus.o XTBWikiplexusArticle.o XTBWikiplexusArticleFormat1.o XTBWikiplexusCollapsibleList.o XTBWikiplexusDictionary.o XTBWikiplexusFamilyTree.o XTBWikiplexusFootnoteExtension.o XTBWikiplexusGalleryExtension.o XTBWikiplexusInfobox.o XTBWikiplexusIsoDate.o XTBWikiplexusIterator.o XTBWikiplexusMathCodizeExtension.o XTBWikiplexusParser.o XTBWikiplexusParserConfig.o XTBWikiplexusSidebar.o XTBWikiplexusSiteInfo.o XTBWikiplexusSourceExtension.o commondlg.o i18n.o main.o platform.o XTBHGGothicData.o twDialog.o twDimmer.o twMsgBox.o twButton.o twCheckBox.o twLabel.o twRadioBtn.o twApp.o twEvent.o twException.o twInvocation.o twObject.o twSDLEvent.o twSDLSemaphore.o twSemaphore.o twStrConv.o twTimer.o twTimerWithInvocation.o twTopWnd.o twTypes.o twWnd.o twExposureFont.o twFont.o twVGAFont.o twDC.o twSDLDC.o twSDLDCXPMLoader.o twBaseSkin.o BlockElements.o CSSColors.o Entities.o HTMLElements.o Styles.o TWBasePageNameVariable.o TWConstantParserVariable.o TWDateParserVariable.o TWDefaultSortParserFunction.o TWDiagnostics.o TWDisplayTitleParserFunction.o TWElement.o TWExpressionEvaluator.o TWExpressionParserFunction.o TWExpressionReader.o TWFormatNumParserFunction.o TWFullPageNameVariable.o TWGrammarParserFunction.o TWHTMLBodyElement.o TWHTMLBuilder.o TWHTMLElement.o TWHTMLStyle.o TWHTMLStyleProxy.o TWHTMLStylesheet.o TWHTMLText.o TWIfEqParserFunction.o TWIfErrorParserFunction.o TWIfExprParserFunction.o TWIfParserFunction.o TWIgnoreParserFunction.o TWNamespaceAliasParserFunction.o TWNamespaceVariable.o TWNode.o TWNumber.o TWPadLeftParserFunction.o TWPadRightParserFunction.o TWPageNameVariable.o TWParser.o TWParserConfig.o TWParserExtension.o TWParserFunction.o TWParserVariable.o TWPassThroughParserFunction.o TWPluralParserFunction.o TWPostparsedParserFunction.o TWPreparsedParserFunction.o TWPreprocessor.o TWPreprocessorAccum.o TWPreprocessorAttribute.o TWPreprocessorFrame.o TWPreprocessorNode.o TWPreprocessorStack.o TWPreprocessorTemplateFrame.o TWPreprocessorText.o TWRandomSelectionExtension.o TWReader.o TWRel2AbsParserFunction.o TWRenderBR.o TWRenderBlock.o TWRenderBox.o TWRenderBoxModelObject.o TWRenderDC.o TWRenderFlowContent.o TWRenderFlowInline.o TWRenderFlowLine.o TWRenderFlowObject.o TWRenderImage.o TWRenderInline.o TWRenderListItem.o TWRenderListMarker.o TWRenderManager.o TWRenderObject.o TWRenderReplaced.o TWRenderTable.o TWRenderTableCell.o TWRenderTableCol.o TWRenderTableRow.o TWRenderText.o TWRenderView.o TWSimpleParserFunction.o TWStandardStyle.o TWSubPageNameVariable.o TWSwitchParserFunction.o TWTitlePartsParserFunction.o TWTransformParserFunction.o TWUtils.o TWVectorStyle.o OBSelector.o TPLArray.o TPLDictionary.o TPLException.o TPLNumber.o TPLObject.o TPLPropertyListSerialization.o TPLString.o tinyxml.o tinyxmlerror.o tinyxmlparser.o H2v2.o idct.o jpegdecoder.o xz_crc32.o xz_dec_lzma2.o xz_dec_stream.o resource.o +resource.o: ../XTBook.rc + $(WINDRES) ../XTBook.rc resource.o +OBJS= TWRenderDCTcw.o TWRenderManagerTcw.o TWViewer.o TWViewerImageManager.o XTBAboutDialog.o XTBActionMenuItem.o XTBArticle.o XTBBrowser.o XTBButtonMenuItem.o XTBContentsChooser.o XTBContentsDataSource.o XTBCoreDictionaryTypeRegister.o XTBDialogSheet.o XTBDicDBMemoryCache.o XTBDicDBReader.o XTBDictionary.o XTBDictionaryIterator.o XTBDictionaryType.o XTBDocument.o XTBDrawTest.o XTBEventManager.o XTBException.o XTBFileStream.o XTBFont.o XTBFont1Bit.o XTBFont4Bit.o XTBFootnoteView.o XTBHGGothic.o XTBHGGothicAA.o XTBHistory.o XTBImage.o XTBImageArticle.o XTBImageComplex.o XTBImageComplexArticle.o XTBImageComplexDictionary.o XTBImageComplexIterator.o XTBImageLoader.o XTBIndexDBReader.o XTBJpegLoader.o XTBLabelMenuItem.o XTBListView.o XTBListViewDataSource.o XTBListViewTest.o XTBMainWindow.o XTBMemoryStream.o XTBMenu.o XTBMenuItem.o XTBNotificationCenter.o XTBOverlay.o XTBPlainArticle.o XTBPreferenceLocaleDataSource.o XTBPreferenceWindow.o XTBProgressOverlay.o XTBRaxDecompressor.o XTBRichgelJpegStream.o XTBRomajiTable.o XTBRootPanel.o XTBRootWindow.o XTBSampleDictionary.o XTBSampleDictionaryArticle.o XTBSampleDictionaryImageArticle.o XTBSampleDictionaryIterator.o XTBSampleDictionaryType.o XTBScrollView.o XTBScrollViewTest.o XTBSearchBar.o XTBSearchErrorView.o XTBSearchView.o XTBSearchViewDataSource.o XTBSeparatorMenuItem.o XTBSkin.o XTBSoftKeyboard.o XTBStartPageBookmarkDataSource.o XTBStartPageHistoryDataSource.o XTBStartPageList.o XTBStartPageListDataSource.o XTBStartPageView.o XTBStream.o XTBStringTable.o XTBStringTableFileHandle.o XTBTabBar.o XTBTabPage.o XTBTestWindow.o XTBTextBox.o XTBTextField.o XTBTextFieldTest.o XTBURL.o XTBUserDefaults.o XTBViewer.o XTBViewerTest.o XTBWikiplexus.o XTBWikiplexusArticle.o XTBWikiplexusArticleFormat1.o XTBWikiplexusCollapsibleList.o XTBWikiplexusDictionary.o XTBWikiplexusFamilyTree.o XTBWikiplexusFootnoteExtension.o XTBWikiplexusGalleryExtension.o XTBWikiplexusInfobox.o XTBWikiplexusIsoDate.o XTBWikiplexusIterator.o XTBWikiplexusMathCodizeExtension.o XTBWikiplexusParser.o XTBWikiplexusParserConfig.o XTBWikiplexusSidebar.o XTBWikiplexusSiteInfo.o XTBWikiplexusSourceExtension.o commondlg.o i18n.o main.o platform.o XTBHGGothicData.o twDialog.o twDimmer.o twMsgBox.o twButton.o twCheckBox.o twLabel.o twRadioBtn.o twApp.o twEvent.o twException.o twInvocation.o twObject.o twSDLEvent.o twSDLSemaphore.o twSemaphore.o twStrConv.o twTimer.o twTimerWithInvocation.o twTopWnd.o twTypes.o twWnd.o twExposureFont.o twFont.o twVGAFont.o twDC.o twSDLDC.o twSDLDCXPMLoader.o twBaseSkin.o BlockElements.o CSSColors.o Entities.o HTMLElements.o Styles.o TWBasePageNameVariable.o TWConstantParserVariable.o TWDateParserVariable.o TWDefaultSortParserFunction.o TWDiagnostics.o TWDisplayTitleParserFunction.o TWElement.o TWExpressionEvaluator.o TWExpressionParserFunction.o TWExpressionReader.o TWFormatNumParserFunction.o TWFullPageNameVariable.o TWGrammarParserFunction.o TWHTMLBodyElement.o TWHTMLBuilder.o TWHTMLElement.o TWHTMLStyle.o TWHTMLStyleProxy.o TWHTMLStylesheet.o TWHTMLText.o TWIfEqParserFunction.o TWIfErrorParserFunction.o TWIfExprParserFunction.o TWIfParserFunction.o TWIgnoreParserFunction.o TWNamespaceAliasParserFunction.o TWNamespaceVariable.o TWNode.o TWNumber.o TWPadLeftParserFunction.o TWPadRightParserFunction.o TWPageNameVariable.o TWParser.o TWParserConfig.o TWParserExtension.o TWParserFunction.o TWParserVariable.o TWPassThroughParserFunction.o TWPluralParserFunction.o TWPostparsedParserFunction.o TWPreparsedParserFunction.o TWPreprocessor.o TWPreprocessorAccum.o TWPreprocessorAttribute.o TWPreprocessorFrame.o TWPreprocessorNode.o TWPreprocessorStack.o TWPreprocessorTemplateFrame.o TWPreprocessorText.o TWRandomSelectionExtension.o TWReader.o TWRel2AbsParserFunction.o TWRenderBR.o TWRenderBlock.o TWRenderBox.o TWRenderBoxModelObject.o TWRenderDC.o TWRenderFlowContent.o TWRenderFlowInline.o TWRenderFlowLine.o TWRenderFlowObject.o TWRenderImage.o TWRenderInline.o TWRenderListItem.o TWRenderListMarker.o TWRenderManager.o TWRenderObject.o TWRenderReplaced.o TWRenderTable.o TWRenderTableCell.o TWRenderTableCol.o TWRenderTableRow.o TWRenderText.o TWRenderView.o TWSimpleParserFunction.o TWStandardStyle.o TWSubPageNameVariable.o TWSwitchParserFunction.o TWTitlePartsParserFunction.o TWTransformParserFunction.o TWUtils.o TWVectorStyle.o OBSelector.o TPLArray.o TPLDictionary.o TPLException.o TPLNumber.o TPLObject.o TPLPropertyListSerialization.o TPLString.o tinyxml.o tinyxmlerror.o tinyxmlparser.o jpgd.o xz_crc32.o xz_dec_lzma2.o xz_dec_stream.o resource.o PCPREFIXHEADER=XTBook_Prefix.pch.gch diff --git a/build.linux/Makefile b/build.linux/Makefile index 1ad836c..813273e 100644 --- a/build.linux/Makefile +++ b/build.linux/Makefile @@ -1,11 +1,11 @@ CC=gcc CXX=g++ LD=g++ -CCFLAGS= -I$(SRCPATH)/tcw/include -I$(SRCPATH) -I/usr/include/SDL -DEV_PLATFORM_GENERICPOSIX -DUNICODE -D_UNICODE -Os +CCFLAGS= -I$(SRCPATH)/tcw/include -I$(SRCPATH) -I/usr/include/SDL -DEV_PLATFORM_GENERICPOSIX -DUNICODE -D_UNICODE -O3 CXXFLAGS=$(CCFLAGS) --std=gnu++03 -LDFLAGS=-lSDLmain -lSDL +LDFLAGS=-lSDLmain -lSDL TARGET=xtbook -PACKAGE=build +PACKAGE=XTBook-0.2.7-Linux .PHONY: all clean @@ -23,7 +23,7 @@ $(TARGET): $(OBJS) packaging: $(TARGET) mkdir -p $(PACKAGE) cp $(TARGET) $(PACKAGE) - cp -r ../StartupItems $(PACKAGE) + mkdir -p $(PACKAGE)/StartupItems cp -r ../Languages $(PACKAGE) cp -r ../InternalDictionaries $(PACKAGE) cp -r ../Help $(PACKAGE) diff --git a/build.linux/Makefile.i b/build.linux/Makefile.i index e6296b8..5d106d2 100644 --- a/build.linux/Makefile.i +++ b/build.linux/Makefile.i @@ -480,17 +480,13 @@ tinyxmlerror.o: ../TinyXML/tinyxmlerror.cpp XTBook_Prefix.pch.gch $(CXX) -include XTBook_Prefix.pch -c ../TinyXML/tinyxmlerror.cpp -o tinyxmlerror.o $(CFLAGS) $(CXXFLAGS) -I.. tinyxmlparser.o: ../TinyXML/tinyxmlparser.cpp XTBook_Prefix.pch.gch $(CXX) -include XTBook_Prefix.pch -c ../TinyXML/tinyxmlparser.cpp -o tinyxmlparser.o $(CFLAGS) $(CXXFLAGS) -I.. -H2v2.o: ../RichgelJpeg/H2v2.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/H2v2.cpp -o H2v2.o $(CFLAGS) $(CXXFLAGS) -I.. -idct.o: ../RichgelJpeg/idct.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/idct.cpp -o idct.o $(CFLAGS) $(CXXFLAGS) -I.. -jpegdecoder.o: ../RichgelJpeg/jpegdecoder.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/jpegdecoder.cpp -o jpegdecoder.o $(CFLAGS) $(CXXFLAGS) -I.. +jpgd.o: ../RichgelJpeg/jpgd.cpp XTBook_Prefix.pch.gch + $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/jpgd.cpp -o jpgd.o $(CFLAGS) $(CXXFLAGS) -DJPGD_USE_SSE2=0 -I.. xz_crc32.o: ../XZEmbedded/xz_crc32.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_crc32.c -o xz_crc32.o $(CFLAGS) xz_dec_lzma2.o: ../XZEmbedded/xz_dec_lzma2.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_dec_lzma2.c -o xz_dec_lzma2.o $(CFLAGS) xz_dec_stream.o: ../XZEmbedded/xz_dec_stream.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_dec_stream.c -o xz_dec_stream.o $(CFLAGS) -OBJS= TWRenderDCTcw.o TWRenderManagerTcw.o TWViewer.o TWViewerImageManager.o XTBAboutDialog.o XTBActionMenuItem.o XTBArticle.o XTBBrowser.o XTBButtonMenuItem.o XTBContentsChooser.o XTBContentsDataSource.o XTBCoreDictionaryTypeRegister.o XTBDialogSheet.o XTBDicDBMemoryCache.o XTBDicDBReader.o XTBDictionary.o XTBDictionaryIterator.o XTBDictionaryType.o XTBDocument.o XTBDrawTest.o XTBEventManager.o XTBException.o XTBFileStream.o XTBFont.o XTBFont1Bit.o XTBFont4Bit.o XTBFootnoteView.o XTBHGGothic.o XTBHGGothicAA.o XTBHistory.o XTBImage.o XTBImageArticle.o XTBImageComplex.o XTBImageComplexArticle.o XTBImageComplexDictionary.o XTBImageComplexIterator.o XTBImageLoader.o XTBIndexDBReader.o XTBJpegLoader.o XTBLabelMenuItem.o XTBListView.o XTBListViewDataSource.o XTBListViewTest.o XTBMainWindow.o XTBMemoryStream.o XTBMenu.o XTBMenuItem.o XTBNotificationCenter.o XTBOverlay.o XTBPlainArticle.o XTBPreferenceLocaleDataSource.o XTBPreferenceWindow.o XTBProgressOverlay.o XTBRaxDecompressor.o XTBRichgelJpegStream.o XTBRomajiTable.o XTBRootPanel.o XTBRootWindow.o XTBSampleDictionary.o XTBSampleDictionaryArticle.o XTBSampleDictionaryImageArticle.o XTBSampleDictionaryIterator.o XTBSampleDictionaryType.o XTBScrollView.o XTBScrollViewTest.o XTBSearchBar.o XTBSearchErrorView.o XTBSearchView.o XTBSearchViewDataSource.o XTBSeparatorMenuItem.o XTBSkin.o XTBSoftKeyboard.o XTBStartPageBookmarkDataSource.o XTBStartPageHistoryDataSource.o XTBStartPageList.o XTBStartPageListDataSource.o XTBStartPageView.o XTBStream.o XTBStringTable.o XTBStringTableFileHandle.o XTBTabBar.o XTBTabPage.o XTBTestWindow.o XTBTextBox.o XTBTextField.o XTBTextFieldTest.o XTBURL.o XTBUserDefaults.o XTBViewer.o XTBViewerTest.o XTBWikiplexus.o XTBWikiplexusArticle.o XTBWikiplexusArticleFormat1.o XTBWikiplexusCollapsibleList.o XTBWikiplexusDictionary.o XTBWikiplexusFamilyTree.o XTBWikiplexusFootnoteExtension.o XTBWikiplexusGalleryExtension.o XTBWikiplexusInfobox.o XTBWikiplexusIsoDate.o XTBWikiplexusIterator.o XTBWikiplexusMathCodizeExtension.o XTBWikiplexusParser.o XTBWikiplexusParserConfig.o XTBWikiplexusSidebar.o XTBWikiplexusSiteInfo.o XTBWikiplexusSourceExtension.o commondlg.o i18n.o main.o platform.o XTBHGGothicData.o twDialog.o twDimmer.o twMsgBox.o twButton.o twCheckBox.o twLabel.o twRadioBtn.o twApp.o twEvent.o twException.o twInvocation.o twObject.o twSDLEvent.o twSDLSemaphore.o twSemaphore.o twStrConv.o twTimer.o twTimerWithInvocation.o twTopWnd.o twTypes.o twWnd.o twExposureFont.o twFont.o twVGAFont.o twDC.o twSDLDC.o twSDLDCXPMLoader.o twBaseSkin.o BlockElements.o CSSColors.o Entities.o HTMLElements.o Styles.o TWBasePageNameVariable.o TWConstantParserVariable.o TWDateParserVariable.o TWDefaultSortParserFunction.o TWDiagnostics.o TWDisplayTitleParserFunction.o TWElement.o TWExpressionEvaluator.o TWExpressionParserFunction.o TWExpressionReader.o TWFormatNumParserFunction.o TWFullPageNameVariable.o TWGrammarParserFunction.o TWHTMLBodyElement.o TWHTMLBuilder.o TWHTMLElement.o TWHTMLStyle.o TWHTMLStyleProxy.o TWHTMLStylesheet.o TWHTMLText.o TWIfEqParserFunction.o TWIfErrorParserFunction.o TWIfExprParserFunction.o TWIfParserFunction.o TWIgnoreParserFunction.o TWNamespaceAliasParserFunction.o TWNamespaceVariable.o TWNode.o TWNumber.o TWPadLeftParserFunction.o TWPadRightParserFunction.o TWPageNameVariable.o TWParser.o TWParserConfig.o TWParserExtension.o TWParserFunction.o TWParserVariable.o TWPassThroughParserFunction.o TWPluralParserFunction.o TWPostparsedParserFunction.o TWPreparsedParserFunction.o TWPreprocessor.o TWPreprocessorAccum.o TWPreprocessorAttribute.o TWPreprocessorFrame.o TWPreprocessorNode.o TWPreprocessorStack.o TWPreprocessorTemplateFrame.o TWPreprocessorText.o TWRandomSelectionExtension.o TWReader.o TWRel2AbsParserFunction.o TWRenderBR.o TWRenderBlock.o TWRenderBox.o TWRenderBoxModelObject.o TWRenderDC.o TWRenderFlowContent.o TWRenderFlowInline.o TWRenderFlowLine.o TWRenderFlowObject.o TWRenderImage.o TWRenderInline.o TWRenderListItem.o TWRenderListMarker.o TWRenderManager.o TWRenderObject.o TWRenderReplaced.o TWRenderTable.o TWRenderTableCell.o TWRenderTableCol.o TWRenderTableRow.o TWRenderText.o TWRenderView.o TWSimpleParserFunction.o TWStandardStyle.o TWSubPageNameVariable.o TWSwitchParserFunction.o TWTitlePartsParserFunction.o TWTransformParserFunction.o TWUtils.o TWVectorStyle.o OBSelector.o TPLArray.o TPLDictionary.o TPLException.o TPLNumber.o TPLObject.o TPLPropertyListSerialization.o TPLString.o tinyxml.o tinyxmlerror.o tinyxmlparser.o H2v2.o idct.o jpegdecoder.o xz_crc32.o xz_dec_lzma2.o xz_dec_stream.o +OBJS= TWRenderDCTcw.o TWRenderManagerTcw.o TWViewer.o TWViewerImageManager.o XTBAboutDialog.o XTBActionMenuItem.o XTBArticle.o XTBBrowser.o XTBButtonMenuItem.o XTBContentsChooser.o XTBContentsDataSource.o XTBCoreDictionaryTypeRegister.o XTBDialogSheet.o XTBDicDBMemoryCache.o XTBDicDBReader.o XTBDictionary.o XTBDictionaryIterator.o XTBDictionaryType.o XTBDocument.o XTBDrawTest.o XTBEventManager.o XTBException.o XTBFileStream.o XTBFont.o XTBFont1Bit.o XTBFont4Bit.o XTBFootnoteView.o XTBHGGothic.o XTBHGGothicAA.o XTBHistory.o XTBImage.o XTBImageArticle.o XTBImageComplex.o XTBImageComplexArticle.o XTBImageComplexDictionary.o XTBImageComplexIterator.o XTBImageLoader.o XTBIndexDBReader.o XTBJpegLoader.o XTBLabelMenuItem.o XTBListView.o XTBListViewDataSource.o XTBListViewTest.o XTBMainWindow.o XTBMemoryStream.o XTBMenu.o XTBMenuItem.o XTBNotificationCenter.o XTBOverlay.o XTBPlainArticle.o XTBPreferenceLocaleDataSource.o XTBPreferenceWindow.o XTBProgressOverlay.o XTBRaxDecompressor.o XTBRichgelJpegStream.o XTBRomajiTable.o XTBRootPanel.o XTBRootWindow.o XTBSampleDictionary.o XTBSampleDictionaryArticle.o XTBSampleDictionaryImageArticle.o XTBSampleDictionaryIterator.o XTBSampleDictionaryType.o XTBScrollView.o XTBScrollViewTest.o XTBSearchBar.o XTBSearchErrorView.o XTBSearchView.o XTBSearchViewDataSource.o XTBSeparatorMenuItem.o XTBSkin.o XTBSoftKeyboard.o XTBStartPageBookmarkDataSource.o XTBStartPageHistoryDataSource.o XTBStartPageList.o XTBStartPageListDataSource.o XTBStartPageView.o XTBStream.o XTBStringTable.o XTBStringTableFileHandle.o XTBTabBar.o XTBTabPage.o XTBTestWindow.o XTBTextBox.o XTBTextField.o XTBTextFieldTest.o XTBURL.o XTBUserDefaults.o XTBViewer.o XTBViewerTest.o XTBWikiplexus.o XTBWikiplexusArticle.o XTBWikiplexusArticleFormat1.o XTBWikiplexusCollapsibleList.o XTBWikiplexusDictionary.o XTBWikiplexusFamilyTree.o XTBWikiplexusFootnoteExtension.o XTBWikiplexusGalleryExtension.o XTBWikiplexusInfobox.o XTBWikiplexusIsoDate.o XTBWikiplexusIterator.o XTBWikiplexusMathCodizeExtension.o XTBWikiplexusParser.o XTBWikiplexusParserConfig.o XTBWikiplexusSidebar.o XTBWikiplexusSiteInfo.o XTBWikiplexusSourceExtension.o commondlg.o i18n.o main.o platform.o XTBHGGothicData.o twDialog.o twDimmer.o twMsgBox.o twButton.o twCheckBox.o twLabel.o twRadioBtn.o twApp.o twEvent.o twException.o twInvocation.o twObject.o twSDLEvent.o twSDLSemaphore.o twSemaphore.o twStrConv.o twTimer.o twTimerWithInvocation.o twTopWnd.o twTypes.o twWnd.o twExposureFont.o twFont.o twVGAFont.o twDC.o twSDLDC.o twSDLDCXPMLoader.o twBaseSkin.o BlockElements.o CSSColors.o Entities.o HTMLElements.o Styles.o TWBasePageNameVariable.o TWConstantParserVariable.o TWDateParserVariable.o TWDefaultSortParserFunction.o TWDiagnostics.o TWDisplayTitleParserFunction.o TWElement.o TWExpressionEvaluator.o TWExpressionParserFunction.o TWExpressionReader.o TWFormatNumParserFunction.o TWFullPageNameVariable.o TWGrammarParserFunction.o TWHTMLBodyElement.o TWHTMLBuilder.o TWHTMLElement.o TWHTMLStyle.o TWHTMLStyleProxy.o TWHTMLStylesheet.o TWHTMLText.o TWIfEqParserFunction.o TWIfErrorParserFunction.o TWIfExprParserFunction.o TWIfParserFunction.o TWIgnoreParserFunction.o TWNamespaceAliasParserFunction.o TWNamespaceVariable.o TWNode.o TWNumber.o TWPadLeftParserFunction.o TWPadRightParserFunction.o TWPageNameVariable.o TWParser.o TWParserConfig.o TWParserExtension.o TWParserFunction.o TWParserVariable.o TWPassThroughParserFunction.o TWPluralParserFunction.o TWPostparsedParserFunction.o TWPreparsedParserFunction.o TWPreprocessor.o TWPreprocessorAccum.o TWPreprocessorAttribute.o TWPreprocessorFrame.o TWPreprocessorNode.o TWPreprocessorStack.o TWPreprocessorTemplateFrame.o TWPreprocessorText.o TWRandomSelectionExtension.o TWReader.o TWRel2AbsParserFunction.o TWRenderBR.o TWRenderBlock.o TWRenderBox.o TWRenderBoxModelObject.o TWRenderDC.o TWRenderFlowContent.o TWRenderFlowInline.o TWRenderFlowLine.o TWRenderFlowObject.o TWRenderImage.o TWRenderInline.o TWRenderListItem.o TWRenderListMarker.o TWRenderManager.o TWRenderObject.o TWRenderReplaced.o TWRenderTable.o TWRenderTableCell.o TWRenderTableCol.o TWRenderTableRow.o TWRenderText.o TWRenderView.o TWSimpleParserFunction.o TWStandardStyle.o TWSubPageNameVariable.o TWSwitchParserFunction.o TWTitlePartsParserFunction.o TWTransformParserFunction.o TWUtils.o TWVectorStyle.o OBSelector.o TPLArray.o TPLDictionary.o TPLException.o TPLNumber.o TPLObject.o TPLPropertyListSerialization.o TPLString.o tinyxml.o tinyxmlerror.o tinyxmlparser.o jpgd.o xz_crc32.o xz_dec_lzma2.o xz_dec_stream.o PCPREFIXHEADER=XTBook_Prefix.pch.gch diff --git a/build.mingw32/Makefile b/build.mingw32/Makefile index bd66f0b..fa46260 100644 --- a/build.mingw32/Makefile +++ b/build.mingw32/Makefile @@ -1,4 +1,4 @@ -SDL=/mnt/c/Users/watamario15/Documents/wata/Git/SDL-1.2/build-mingw32/.libs +SDL=/mnt/c/Users/watamario15/Documents/wata/Git/SDL-1.2/build.mingw32/.libs SDLINCLUDE=/mnt/c/Users/watamario15/Documents/wata/Git/SDL-1.2/include HOST=i686-w64-mingw32- CC=$(HOST)gcc @@ -6,11 +6,11 @@ CXX=$(HOST)g++ LD=$(HOST)g++ STRIP=$(HOST)strip WINDRES=$(HOST)windres -CCFLAGS= -I$(SRCPATH)/tcw/include -I$(SRCPATH) -I$(SDLINCLUDE) -DEV_PLATFORM_WIN32 -DUNICODE -D_UNICODE -DEV_UNSAFE_SWPRINTF -mwin32 -Os -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DNDEBUG +CCFLAGS= -I$(SRCPATH)/tcw/include -I$(SRCPATH) -I$(SDLINCLUDE) -DEV_PLATFORM_WIN32 -DUNICODE -D_UNICODE -DEV_UNSAFE_SWPRINTF -mwin32 -O3 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DNDEBUG CXXFLAGS=$(CCFLAGS) --std=gnu++03 LDFLAGS=-L$(SDL) -lmingw32 -lSDLmain -lSDL -mwindows -lm -luser32 -lgdi32 -lwinmm -ldxguid -static -lstdc++ TARGET=XTBook.exe -PACKAGE=build +PACKAGE=XTBook-0.2.7-Windows .PHONY: all clean @@ -29,7 +29,7 @@ $(TARGET): $(OBJS) packaging: $(TARGET) mkdir -p $(PACKAGE) cp $(TARGET) $(PACKAGE) - cp -r ../StartupItems $(PACKAGE) + mkdir -p $(PACKAGE)/StartupItems cp -r ../Languages $(PACKAGE) cp -r ../InternalDictionaries $(PACKAGE) cp -r ../Help $(PACKAGE) diff --git a/build.mingw32/Makefile.i b/build.mingw32/Makefile.i index 52d45a8..d66c48b 100644 --- a/build.mingw32/Makefile.i +++ b/build.mingw32/Makefile.i @@ -480,19 +480,15 @@ tinyxmlerror.o: ../TinyXML/tinyxmlerror.cpp XTBook_Prefix.pch.gch $(CXX) -include XTBook_Prefix.pch -c ../TinyXML/tinyxmlerror.cpp -o tinyxmlerror.o $(CFLAGS) $(CXXFLAGS) -I.. tinyxmlparser.o: ../TinyXML/tinyxmlparser.cpp XTBook_Prefix.pch.gch $(CXX) -include XTBook_Prefix.pch -c ../TinyXML/tinyxmlparser.cpp -o tinyxmlparser.o $(CFLAGS) $(CXXFLAGS) -I.. -H2v2.o: ../RichgelJpeg/H2v2.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/H2v2.cpp -o H2v2.o $(CFLAGS) $(CXXFLAGS) -I.. -idct.o: ../RichgelJpeg/idct.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/idct.cpp -o idct.o $(CFLAGS) $(CXXFLAGS) -I.. -jpegdecoder.o: ../RichgelJpeg/jpegdecoder.cpp XTBook_Prefix.pch.gch - $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/jpegdecoder.cpp -o jpegdecoder.o $(CFLAGS) $(CXXFLAGS) -I.. +jpgd.o: ../RichgelJpeg/jpgd.cpp XTBook_Prefix.pch.gch + $(CXX) -include XTBook_Prefix.pch -c ../RichgelJpeg/jpgd.cpp -o jpgd.o $(CFLAGS) $(CXXFLAGS) -DJPGD_USE_SSE2=0 -I.. xz_crc32.o: ../XZEmbedded/xz_crc32.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_crc32.c -o xz_crc32.o $(CFLAGS) xz_dec_lzma2.o: ../XZEmbedded/xz_dec_lzma2.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_dec_lzma2.c -o xz_dec_lzma2.o $(CFLAGS) xz_dec_stream.o: ../XZEmbedded/xz_dec_stream.c XTBook_Prefix.pch.gch $(CC) -c ../XZEmbedded/xz_dec_stream.c -o xz_dec_stream.o $(CFLAGS) -resource.o: ../xtbook.rc - $(WINDRES) ../xtbook.rc resource.o -OBJS= TWRenderDCTcw.o TWRenderManagerTcw.o TWViewer.o TWViewerImageManager.o XTBAboutDialog.o XTBActionMenuItem.o XTBArticle.o XTBBrowser.o XTBButtonMenuItem.o XTBContentsChooser.o XTBContentsDataSource.o XTBCoreDictionaryTypeRegister.o XTBDialogSheet.o XTBDicDBMemoryCache.o XTBDicDBReader.o XTBDictionary.o XTBDictionaryIterator.o XTBDictionaryType.o XTBDocument.o XTBDrawTest.o XTBEventManager.o XTBException.o XTBFileStream.o XTBFont.o XTBFont1Bit.o XTBFont4Bit.o XTBFootnoteView.o XTBHGGothic.o XTBHGGothicAA.o XTBHistory.o XTBImage.o XTBImageArticle.o XTBImageComplex.o XTBImageComplexArticle.o XTBImageComplexDictionary.o XTBImageComplexIterator.o XTBImageLoader.o XTBIndexDBReader.o XTBJpegLoader.o XTBLabelMenuItem.o XTBListView.o XTBListViewDataSource.o XTBListViewTest.o XTBMainWindow.o XTBMemoryStream.o XTBMenu.o XTBMenuItem.o XTBNotificationCenter.o XTBOverlay.o XTBPlainArticle.o XTBPreferenceLocaleDataSource.o XTBPreferenceWindow.o XTBProgressOverlay.o XTBRaxDecompressor.o XTBRichgelJpegStream.o XTBRomajiTable.o XTBRootPanel.o XTBRootWindow.o XTBSampleDictionary.o XTBSampleDictionaryArticle.o XTBSampleDictionaryImageArticle.o XTBSampleDictionaryIterator.o XTBSampleDictionaryType.o XTBScrollView.o XTBScrollViewTest.o XTBSearchBar.o XTBSearchErrorView.o XTBSearchView.o XTBSearchViewDataSource.o XTBSeparatorMenuItem.o XTBSkin.o XTBSoftKeyboard.o XTBStartPageBookmarkDataSource.o XTBStartPageHistoryDataSource.o XTBStartPageList.o XTBStartPageListDataSource.o XTBStartPageView.o XTBStream.o XTBStringTable.o XTBStringTableFileHandle.o XTBTabBar.o XTBTabPage.o XTBTestWindow.o XTBTextBox.o XTBTextField.o XTBTextFieldTest.o XTBURL.o XTBUserDefaults.o XTBViewer.o XTBViewerTest.o XTBWikiplexus.o XTBWikiplexusArticle.o XTBWikiplexusArticleFormat1.o XTBWikiplexusCollapsibleList.o XTBWikiplexusDictionary.o XTBWikiplexusFamilyTree.o XTBWikiplexusFootnoteExtension.o XTBWikiplexusGalleryExtension.o XTBWikiplexusInfobox.o XTBWikiplexusIsoDate.o XTBWikiplexusIterator.o XTBWikiplexusMathCodizeExtension.o XTBWikiplexusParser.o XTBWikiplexusParserConfig.o XTBWikiplexusSidebar.o XTBWikiplexusSiteInfo.o XTBWikiplexusSourceExtension.o commondlg.o i18n.o main.o platform.o XTBHGGothicData.o twDialog.o twDimmer.o twMsgBox.o twButton.o twCheckBox.o twLabel.o twRadioBtn.o twApp.o twEvent.o twException.o twInvocation.o twObject.o twSDLEvent.o twSDLSemaphore.o twSemaphore.o twStrConv.o twTimer.o twTimerWithInvocation.o twTopWnd.o twTypes.o twWnd.o twExposureFont.o twFont.o twVGAFont.o twDC.o twSDLDC.o twSDLDCXPMLoader.o twBaseSkin.o BlockElements.o CSSColors.o Entities.o HTMLElements.o Styles.o TWBasePageNameVariable.o TWConstantParserVariable.o TWDateParserVariable.o TWDefaultSortParserFunction.o TWDiagnostics.o TWDisplayTitleParserFunction.o TWElement.o TWExpressionEvaluator.o TWExpressionParserFunction.o TWExpressionReader.o TWFormatNumParserFunction.o TWFullPageNameVariable.o TWGrammarParserFunction.o TWHTMLBodyElement.o TWHTMLBuilder.o TWHTMLElement.o TWHTMLStyle.o TWHTMLStyleProxy.o TWHTMLStylesheet.o TWHTMLText.o TWIfEqParserFunction.o TWIfErrorParserFunction.o TWIfExprParserFunction.o TWIfParserFunction.o TWIgnoreParserFunction.o TWNamespaceAliasParserFunction.o TWNamespaceVariable.o TWNode.o TWNumber.o TWPadLeftParserFunction.o TWPadRightParserFunction.o TWPageNameVariable.o TWParser.o TWParserConfig.o TWParserExtension.o TWParserFunction.o TWParserVariable.o TWPassThroughParserFunction.o TWPluralParserFunction.o TWPostparsedParserFunction.o TWPreparsedParserFunction.o TWPreprocessor.o TWPreprocessorAccum.o TWPreprocessorAttribute.o TWPreprocessorFrame.o TWPreprocessorNode.o TWPreprocessorStack.o TWPreprocessorTemplateFrame.o TWPreprocessorText.o TWRandomSelectionExtension.o TWReader.o TWRel2AbsParserFunction.o TWRenderBR.o TWRenderBlock.o TWRenderBox.o TWRenderBoxModelObject.o TWRenderDC.o TWRenderFlowContent.o TWRenderFlowInline.o TWRenderFlowLine.o TWRenderFlowObject.o TWRenderImage.o TWRenderInline.o TWRenderListItem.o TWRenderListMarker.o TWRenderManager.o TWRenderObject.o TWRenderReplaced.o TWRenderTable.o TWRenderTableCell.o TWRenderTableCol.o TWRenderTableRow.o TWRenderText.o TWRenderView.o TWSimpleParserFunction.o TWStandardStyle.o TWSubPageNameVariable.o TWSwitchParserFunction.o TWTitlePartsParserFunction.o TWTransformParserFunction.o TWUtils.o TWVectorStyle.o OBSelector.o TPLArray.o TPLDictionary.o TPLException.o TPLNumber.o TPLObject.o TPLPropertyListSerialization.o TPLString.o tinyxml.o tinyxmlerror.o tinyxmlparser.o H2v2.o idct.o jpegdecoder.o xz_crc32.o xz_dec_lzma2.o xz_dec_stream.o resource.o +resource.o: ../XTBook.rc + $(WINDRES) ../XTBook.rc resource.o +OBJS= TWRenderDCTcw.o TWRenderManagerTcw.o TWViewer.o TWViewerImageManager.o XTBAboutDialog.o XTBActionMenuItem.o XTBArticle.o XTBBrowser.o XTBButtonMenuItem.o XTBContentsChooser.o XTBContentsDataSource.o XTBCoreDictionaryTypeRegister.o XTBDialogSheet.o XTBDicDBMemoryCache.o XTBDicDBReader.o XTBDictionary.o XTBDictionaryIterator.o XTBDictionaryType.o XTBDocument.o XTBDrawTest.o XTBEventManager.o XTBException.o XTBFileStream.o XTBFont.o XTBFont1Bit.o XTBFont4Bit.o XTBFootnoteView.o XTBHGGothic.o XTBHGGothicAA.o XTBHistory.o XTBImage.o XTBImageArticle.o XTBImageComplex.o XTBImageComplexArticle.o XTBImageComplexDictionary.o XTBImageComplexIterator.o XTBImageLoader.o XTBIndexDBReader.o XTBJpegLoader.o XTBLabelMenuItem.o XTBListView.o XTBListViewDataSource.o XTBListViewTest.o XTBMainWindow.o XTBMemoryStream.o XTBMenu.o XTBMenuItem.o XTBNotificationCenter.o XTBOverlay.o XTBPlainArticle.o XTBPreferenceLocaleDataSource.o XTBPreferenceWindow.o XTBProgressOverlay.o XTBRaxDecompressor.o XTBRichgelJpegStream.o XTBRomajiTable.o XTBRootPanel.o XTBRootWindow.o XTBSampleDictionary.o XTBSampleDictionaryArticle.o XTBSampleDictionaryImageArticle.o XTBSampleDictionaryIterator.o XTBSampleDictionaryType.o XTBScrollView.o XTBScrollViewTest.o XTBSearchBar.o XTBSearchErrorView.o XTBSearchView.o XTBSearchViewDataSource.o XTBSeparatorMenuItem.o XTBSkin.o XTBSoftKeyboard.o XTBStartPageBookmarkDataSource.o XTBStartPageHistoryDataSource.o XTBStartPageList.o XTBStartPageListDataSource.o XTBStartPageView.o XTBStream.o XTBStringTable.o XTBStringTableFileHandle.o XTBTabBar.o XTBTabPage.o XTBTestWindow.o XTBTextBox.o XTBTextField.o XTBTextFieldTest.o XTBURL.o XTBUserDefaults.o XTBViewer.o XTBViewerTest.o XTBWikiplexus.o XTBWikiplexusArticle.o XTBWikiplexusArticleFormat1.o XTBWikiplexusCollapsibleList.o XTBWikiplexusDictionary.o XTBWikiplexusFamilyTree.o XTBWikiplexusFootnoteExtension.o XTBWikiplexusGalleryExtension.o XTBWikiplexusInfobox.o XTBWikiplexusIsoDate.o XTBWikiplexusIterator.o XTBWikiplexusMathCodizeExtension.o XTBWikiplexusParser.o XTBWikiplexusParserConfig.o XTBWikiplexusSidebar.o XTBWikiplexusSiteInfo.o XTBWikiplexusSourceExtension.o commondlg.o i18n.o main.o platform.o XTBHGGothicData.o twDialog.o twDimmer.o twMsgBox.o twButton.o twCheckBox.o twLabel.o twRadioBtn.o twApp.o twEvent.o twException.o twInvocation.o twObject.o twSDLEvent.o twSDLSemaphore.o twSemaphore.o twStrConv.o twTimer.o twTimerWithInvocation.o twTopWnd.o twTypes.o twWnd.o twExposureFont.o twFont.o twVGAFont.o twDC.o twSDLDC.o twSDLDCXPMLoader.o twBaseSkin.o BlockElements.o CSSColors.o Entities.o HTMLElements.o Styles.o TWBasePageNameVariable.o TWConstantParserVariable.o TWDateParserVariable.o TWDefaultSortParserFunction.o TWDiagnostics.o TWDisplayTitleParserFunction.o TWElement.o TWExpressionEvaluator.o TWExpressionParserFunction.o TWExpressionReader.o TWFormatNumParserFunction.o TWFullPageNameVariable.o TWGrammarParserFunction.o TWHTMLBodyElement.o TWHTMLBuilder.o TWHTMLElement.o TWHTMLStyle.o TWHTMLStyleProxy.o TWHTMLStylesheet.o TWHTMLText.o TWIfEqParserFunction.o TWIfErrorParserFunction.o TWIfExprParserFunction.o TWIfParserFunction.o TWIgnoreParserFunction.o TWNamespaceAliasParserFunction.o TWNamespaceVariable.o TWNode.o TWNumber.o TWPadLeftParserFunction.o TWPadRightParserFunction.o TWPageNameVariable.o TWParser.o TWParserConfig.o TWParserExtension.o TWParserFunction.o TWParserVariable.o TWPassThroughParserFunction.o TWPluralParserFunction.o TWPostparsedParserFunction.o TWPreparsedParserFunction.o TWPreprocessor.o TWPreprocessorAccum.o TWPreprocessorAttribute.o TWPreprocessorFrame.o TWPreprocessorNode.o TWPreprocessorStack.o TWPreprocessorTemplateFrame.o TWPreprocessorText.o TWRandomSelectionExtension.o TWReader.o TWRel2AbsParserFunction.o TWRenderBR.o TWRenderBlock.o TWRenderBox.o TWRenderBoxModelObject.o TWRenderDC.o TWRenderFlowContent.o TWRenderFlowInline.o TWRenderFlowLine.o TWRenderFlowObject.o TWRenderImage.o TWRenderInline.o TWRenderListItem.o TWRenderListMarker.o TWRenderManager.o TWRenderObject.o TWRenderReplaced.o TWRenderTable.o TWRenderTableCell.o TWRenderTableCol.o TWRenderTableRow.o TWRenderText.o TWRenderView.o TWSimpleParserFunction.o TWStandardStyle.o TWSubPageNameVariable.o TWSwitchParserFunction.o TWTitlePartsParserFunction.o TWTransformParserFunction.o TWUtils.o TWVectorStyle.o OBSelector.o TPLArray.o TPLDictionary.o TPLException.o TPLNumber.o TPLObject.o TPLPropertyListSerialization.o TPLString.o tinyxml.o tinyxmlerror.o tinyxmlparser.o jpgd.o xz_crc32.o xz_dec_lzma2.o xz_dec_stream.o resource.o PCPREFIXHEADER=XTBook_Prefix.pch.gch diff --git a/main.cpp b/main.cpp index e2dd3db..2f4b600 100644 --- a/main.cpp +++ b/main.cpp @@ -102,14 +102,14 @@ static void errorExit(const std::wstring& msg){ /** Short version. */ std::wstring XTBShortVersionInformation(){ - return L"XTBook-0.2.6"; // removed russian(setSoftKeyboardVisible) from XTBBrowser + return L"XTBook-0.2.7"; // removed russian(setSoftKeyboardVisible) from XTBBrowser //return L"XTBook-0.2.6-russian"; } /** Full version information. */ std::wstring XTBLongVersionInformation(){ return XTBShortVersionInformation()+L" Copyright 2011-2012 Nexhawks, all rights reserved.\n" - L"Visit http://www.nexhawks.net/ for more informations."; + L"Visit https://www.nexhawks.net/ for more informations."; } void initThreadSafeComponents(); diff --git a/platform.cpp b/platform.cpp index 9b19c68..f5462f6 100644 --- a/platform.cpp +++ b/platform.cpp @@ -374,6 +374,8 @@ static void XTBRunStartupItem(const XTBSysString& path){ #include +#include + static std::string g_argv0; __attribute__((noreturn)) @@ -389,10 +391,10 @@ XTBSysString XTBChooseOpenFile(const std::wstring& typeName, const std::wstring& // ask for the file-name in the console. wprintf(L"*DIALOG* Open File Request\n"); wprintf(L"Type path for %ls (*.%ls):\n", typeName.c_str(), ext.c_str()); - char buf1[4096]; + XTBSysString buf1; // TODO: more safe way instead of gets. - gets(buf1); + std::getline(std::cin, buf1); // return the file name. return buf1; diff --git a/tcw/font/twExposureFont.cpp b/tcw/font/twExposureFont.cpp index 4f3d4c5..4c9449c 100644 --- a/tcw/font/twExposureFont.cpp +++ b/tcw/font/twExposureFont.cpp @@ -49,7 +49,7 @@ twExposureFont::twExposureFont(const std::wstring& name){ int ch; twRect rt; memset(glyphs, 0, sizeof(glyphs)); - sprintf(fn, "%s.cfg", buf); + snprintf(fn, sizeof(fn) / sizeof(fn[0]) - 4, "%s.cfg", buf); f=fopen(fn, "r"); if(f==NULL){ delete fnt; diff --git a/test.txt b/test.txt deleted file mode 100644 index 4b72446..0000000 Binary files a/test.txt and /dev/null differ diff --git a/tools/GenerateCSSColors.cpp b/tools/GenerateCSSColors.cpp index 413793a..4e55cf2 100644 --- a/tools/GenerateCSSColors.cpp +++ b/tools/GenerateCSSColors.cpp @@ -13,18 +13,17 @@ #include #include #include +#include using namespace std; int main(int argc, char **argv){ - char buf[256]; string str; - while(gets(buf)){ - if(buf[0]==0) + while(std::getline(std::cin, str)){ + if(str[0]==0) continue; - if(buf[1]=='!') + if(str[1]=='!') continue; - str=buf; if(str.find('\t')==string::npos) continue; diff --git a/tools/GenerateEntityTable.cpp b/tools/GenerateEntityTable.cpp index 6dc46f9..df6a01b 100644 --- a/tools/GenerateEntityTable.cpp +++ b/tools/GenerateEntityTable.cpp @@ -14,6 +14,8 @@ #include #include +#include + using namespace std; @@ -73,24 +75,23 @@ std::vector splitString(const std::string& str, const std::string& delim } int main(int argc, char **argv){ - char buf[4096]; if(argc==1){ - while(gets(buf)){ - std::string str=buf; + std::string str; + while(std::getline(std::cin, str)){ std::vector strs=splitString(str, ","); printf("registerChar(L\"%s\", (wchar_t)%s);\n", strs[0].c_str(), strs[2].c_str()); } }else if(argc==2){ if(!strcmp(argv[1], "obs")){ - while(gets(buf)){ - std::string str=buf; + std::string str; + while(std::getline(std::cin, str)){ std::vector strs=splitString(str, ","); printf("%s\n", strs[0].c_str()); } }else if(!strcmp(argv[1], "chars")){ int i=0; - while(gets(buf)){ - std::string str=buf; + std::string str; + while(std::getline(std::cin, str)){ std::vector strs=splitString(str, ","); printf("(wchar_t)0x%04x,", atoi(strs[2].c_str())); i++; diff --git a/tools/GenerateRGBTable.cpp b/tools/GenerateRGBTable.cpp index 02d8694..5c78563 100644 --- a/tools/GenerateRGBTable.cpp +++ b/tools/GenerateRGBTable.cpp @@ -13,6 +13,8 @@ #include #include +#include + using namespace std; @@ -29,17 +31,15 @@ static std::string toLower(const std::string& str){ } int main(int argc, char **argv){ - char buf[256]; string str; if(argc==1){ - while(gets(buf)){ - if(buf[0]==0) + while(std::getline(std::cin, str)){ + if(str[0]==0) continue; - if(buf[1]=='!') + if(str[1]=='!') continue; - str=buf; if(str.find('\t')==string::npos) continue; @@ -60,12 +60,11 @@ int main(int argc, char **argv){ puts("USAGE: GenerateRGBTable [MODE]"); puts("MDOES: obs colors"); }else if(!strcmp(argv[1], "obs")){ - while(gets(buf)){ - if(buf[0]==0) + while(std::getline(std::cin, str)){ + if(str[0]==0) continue; - if(buf[1]=='!') + if(str[1]=='!') continue; - str=buf; if(str.find('\t')==string::npos) continue; @@ -83,12 +82,11 @@ int main(int argc, char **argv){ } }else if(!strcmp(argv[1], "colors")){ int i=0; - while(gets(buf)){ - if(buf[0]==0) + while(std::getline(std::cin, str)){ + if(str[0]==0) continue; - if(buf[1]=='!') + if(str[1]=='!') continue; - str=buf; if(str.find('\t')==string::npos) continue; diff --git a/tools/GenerateStringTable.cpp b/tools/GenerateStringTable.cpp index decc080..946a46e 100644 --- a/tools/GenerateStringTable.cpp +++ b/tools/GenerateStringTable.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace std; @@ -24,30 +25,31 @@ static void writeLE32(uint32_t value){ fwrite(buf, 1, 4, stdout); } -static void parseLine(char *line){ +static void parseLine(std::string &line){ { - char *ptr=strchr(line, '#'); - if(ptr) - *ptr=0; + size_t pos = line.find('#'); + if(pos != line.npos) + line.resize(pos); } + + const char *szLine = line.c_str(); - while(*line==' ') - line++; + while(*szLine==' ') + szLine++; - if(*line==13 || *line==10 || *line==0) + if(*szLine==13 || *szLine==10 || *szLine==0) return; - uint32_t length; - length=strlen(line); + size_t length=strlen(szLine); writeLE32(length); - fwrite(line, 1, length, stdout); + fwrite(szLine, 1, length, stdout); } int main(int argc, char **argv){ - char buf[4096]; + std::string buf; if(argc==3){ freopen(argv[1], "r", stdin); @@ -55,7 +57,7 @@ int main(int argc, char **argv){ } - while(gets(buf)){ + while(std::getline(std::cin, buf)){ parseLine(buf); } diff --git a/tools/TWEval.cpp b/tools/TWEval.cpp index ccb4cba..ea5d2b4 100644 --- a/tools/TWEval.cpp +++ b/tools/TWEval.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../TWiki/TWUtils.h" #include "../TWiki/TWExpressionReader.h" @@ -52,8 +53,8 @@ std::wstring TWUtils::evaluateExpression(const std::wstring &expr){ } int main(){ - char buf[32767]; - while(gets(buf)){ + std::string buf; + while(std::getline(std::cin, buf)){ std::wstring s; s=TWUtils::m2w(buf);