Merge pull request #11650 from german77/lle_album

service: am: Add support for LLE Album Applet
This commit is contained in:
Fernando S 2023-10-10 11:47:13 +02:00 committed by GitHub
commit 8151a4d301
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 12216 additions and 247 deletions

View file

@ -168,7 +168,7 @@ if (NOT TARGET LLVM::Demangle)
add_library(LLVM::Demangle ALIAS demangle) add_library(LLVM::Demangle ALIAS demangle)
endif() endif()
add_library(stb stb/stb_dxt.cpp) add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp)
target_include_directories(stb PUBLIC ./stb) target_include_directories(stb PUBLIC ./stb)
add_library(bc_decoder bc_decoder/bc_decoder.cpp) add_library(bc_decoder bc_decoder/bc_decoder.cpp)

7529
externals/stb/stb_image.cpp vendored Normal file

File diff suppressed because it is too large Load diff

772
externals/stb/stb_image.h vendored Normal file
View file

@ -0,0 +1,772 @@
// SPDX-FileCopyrightText: stb http://nothings.org/stb
// SPDX-License-Identifier: MIT
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
#define STB_IMAGE_IMPLEMENTATION
before you include this file in *one* C or C++ file to create the implementation.
// i.e. it should look like this:
#include ...
#include ...
#include ...
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
QUICK NOTES:
Primarily of interest to game developers and other people who can
avoid problematic images and only need the trivial interface
JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
PNG 1/2/4/8/16-bit-per-channel
TGA (not sure what subset, if a subset)
BMP non-1bpp, non-RLE
PSD (composited view only, no extra channels, 8/16 bit-per-channel)
GIF (*comp always reports as 4-channel)
HDR (radiance rgbE format)
PIC (Softimage PIC)
PNM (PPM and PGM binary only)
Animated GIF still needs a proper API, but here's one way to do it:
http://gist.github.com/urraka/685d9a6340b26b830d49
- decode from memory or through FILE (define STBI_NO_STDIO to remove code)
- decode from arbitrary I/O callbacks
- SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
Full documentation under "DOCUMENTATION" below.
LICENSE
See end of file for license information.
RECENT REVISION HISTORY:
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
2.26 (2020-07-13) many minor fixes
2.25 (2020-02-02) fix warnings
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
2.23 (2019-08-11) fix clang static analysis warning
2.22 (2019-03-04) gif fixes, fix warnings
2.21 (2019-02-25) fix typo in comment
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
RGB-format JPEG; remove white matting in PSD;
allocate large structures on the stack;
correct channel count for PNG & BMP
2.10 (2016-01-22) avoid warning introduced in 2.09
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
See end of file for full revision history.
============================ Contributors =========================
Image formats Extensions, features
Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
github:urraka (animated gif) Junggon Kim (PNM comments)
Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit PNG)
Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
Arseny Kapoulkine Simon Breuss (16-bit PNM)
John-Mark Allen
Carmelo J Fdez-Aguera
Bug & warning fixes
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
Phil Jordan Dave Moore Roy Eltham
Hayaki Saito Nathan Reed Won Chun
Luke Graham Johan Duparc Nick Verigakis the Horde3D community
Thomas Ruf Ronny Chevalier github:rlyeh
Janez Zemva John Bartholomew Michal Cichon github:romigrou
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
Cass Everitt Ryamond Barbiero github:grim210
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
Brad Weinberger Matvey Cherevko github:mosra
Luca Sas Alexander Veselov Zack Middleton [reserved]
Ryan C. Gordon [reserved] [reserved]
DO NOT ADD YOUR NAME HERE
Jacko Dirks
To add your name to the credits, pick a random blank space in the middle and fill it.
80% of merge conflicts on stb PRs are due to people adding their name at the end
of the credits.
*/
#ifndef STBI_INCLUDE_STB_IMAGE_H
#define STBI_INCLUDE_STB_IMAGE_H
// DOCUMENTATION
//
// Limitations:
// - no 12-bit-per-channel JPEG
// - no JPEGs with arithmetic coding
// - GIF always returns *comp=4
//
// Basic usage (see HDR discussion below for HDR usage):
// int x,y,n;
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// // ... process data if not NULL ...
// // ... x = width, y = height, n = # 8-bit components per pixel ...
// // ... replace '0' with '1'..'4' to force that many components per pixel
// // ... but 'n' will always be the number that it would have been if you said 0
// stbi_image_free(data);
//
// Standard parameters:
// int *x -- outputs image width in pixels
// int *y -- outputs image height in pixels
// int *channels_in_file -- outputs # of image components in image file
// int desired_channels -- if non-zero, # of image components requested in result
//
// The return value from an image loader is an 'unsigned char *' which points
// to the pixel data, or NULL on an allocation failure or if the image is
// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
// with each pixel consisting of N interleaved 8-bit components; the first
// pixel pointed to is top-left-most in the image. There is no padding between
// image scanlines or between pixels, regardless of format. The number of
// components N is 'desired_channels' if desired_channels is non-zero, or
// *channels_in_file otherwise. If desired_channels is non-zero,
// *channels_in_file has the number of components that _would_ have been
// output otherwise. E.g. if you set desired_channels to 4, you will always
// get RGBA output, but you can check *channels_in_file to see if it's trivially
// opaque because e.g. there were only 3 channels in the source image.
//
// An output image with N components has the following components interleaved
// in this order in each pixel:
//
// N=#comp components
// 1 grey
// 2 grey, alpha
// 3 red, green, blue
// 4 red, green, blue, alpha
//
// If image loading fails for any reason, the return value will be NULL,
// and *x, *y, *channels_in_file will be unchanged. The function
// stbi_failure_reason() can be queried for an extremely brief, end-user
// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
// more user-friendly ones.
//
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
//
// To query the width, height and component count of an image without having to
// decode the full file, you can use the stbi_info family of functions:
//
// int x,y,n,ok;
// ok = stbi_info(filename, &x, &y, &n);
// // returns ok=1 and sets x, y, n if image is a supported format,
// // 0 otherwise.
//
// Note that stb_image pervasively uses ints in its public API for sizes,
// including sizes of memory buffers. This is now part of the API and thus
// hard to change without causing breakage. As a result, the various image
// loaders all have certain limits on image size; these differ somewhat
// by format but generally boil down to either just under 2GB or just under
// 1GB. When the decoded image would be larger than this, stb_image decoding
// will fail.
//
// Additionally, stb_image will reject image files that have any of their
// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
// the only way to have an image with such dimensions load correctly
// is for it to have a rather extreme aspect ratio. Either way, the
// assumption here is that such larger images are likely to be malformed
// or malicious. If you do need to load an image with individual dimensions
// larger than that, and it still fits in the overall size limit, you can
// #define STBI_MAX_DIMENSIONS on your own to be something larger.
//
// ===========================================================================
//
// UNICODE:
//
// If compiling for Windows and you wish to use Unicode filenames, compile
// with
// #define STBI_WINDOWS_UTF8
// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
// Windows wchar_t filenames to utf8.
//
// ===========================================================================
//
// Philosophy
//
// stb libraries are designed with the following priorities:
//
// 1. easy to use
// 2. easy to maintain
// 3. good performance
//
// Sometimes I let "good performance" creep up in priority over "easy to maintain",
// and for best performance I may provide less-easy-to-use APIs that give higher
// performance, in addition to the easy-to-use ones. Nevertheless, it's important
// to keep in mind that from the standpoint of you, a client of this library,
// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
//
// Some secondary priorities arise directly from the first two, some of which
// provide more explicit reasons why performance can't be emphasized.
//
// - Portable ("ease of use")
// - Small source code footprint ("easy to maintain")
// - No dependencies ("ease of use")
//
// ===========================================================================
//
// I/O callbacks
//
// I/O callbacks allow you to read from arbitrary sources, like packaged
// files or some other source. Data read from callbacks are processed
// through a small internal buffer (currently 128 bytes) to try to reduce
// overhead.
//
// The three functions you must define are "read" (reads some bytes of data),
// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
//
// ===========================================================================
//
// SIMD support
//
// The JPEG decoder will try to automatically use SIMD kernels on x86 when
// supported by the compiler. For ARM Neon support, you must explicitly
// request it.
//
// (The old do-it-yourself SIMD API is no longer supported in the current
// code.)
//
// On x86, SSE2 will automatically be used when available based on a run-time
// test; if not, the generic C versions are used as a fall-back. On ARM targets,
// the typical path is to have separate builds for NEON and non-NEON devices
// (at least this is true for iOS and Android). Therefore, the NEON support is
// toggled by a build flag: define STBI_NEON to get NEON loops.
//
// If for some reason you do not want to use any of SIMD code, or if
// you have issues compiling it, you can disable it entirely by
// defining STBI_NO_SIMD.
//
// ===========================================================================
//
// HDR image support (disable by defining STBI_NO_HDR)
//
// stb_image supports loading HDR images in general, and currently the Radiance
// .HDR file format specifically. You can still load any file through the existing
// interface; if you attempt to load an HDR file, it will be automatically remapped
// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
// both of these constants can be reconfigured through this interface:
//
// stbi_hdr_to_ldr_gamma(2.2f);
// stbi_hdr_to_ldr_scale(1.0f);
//
// (note, do not use _inverse_ constants; stbi_image will invert them
// appropriately).
//
// Additionally, there is a new, parallel interface for loading files as
// (linear) floats to preserve the full dynamic range:
//
// float *data = stbi_loadf(filename, &x, &y, &n, 0);
//
// If you load LDR images through this interface, those images will
// be promoted to floating point values, run through the inverse of
// constants corresponding to the above:
//
// stbi_ldr_to_hdr_scale(1.0f);
// stbi_ldr_to_hdr_gamma(2.2f);
//
// Finally, given a filename (or an open file or memory block--see header
// file for details) containing image data, you can query for the "most
// appropriate" interface to use (that is, whether the image is HDR or
// not), using:
//
// stbi_is_hdr(char *filename);
//
// ===========================================================================
//
// iPhone PNG support:
//
// We optionally support converting iPhone-formatted PNGs (which store
// premultiplied BGRA) back to RGB, even though they're internally encoded
// differently. To enable this conversion, call
// stbi_convert_iphone_png_to_rgb(1).
//
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
// pixel to remove any premultiplied alpha *only* if the image file explicitly
// says there's premultiplied data (currently only happens in iPhone images,
// and only if iPhone convert-to-rgb processing is on).
//
// ===========================================================================
//
// ADDITIONAL CONFIGURATION
//
// - You can suppress implementation of any of the decoders to reduce
// your code footprint by #defining one or more of the following
// symbols before creating the implementation.
//
// STBI_NO_JPEG
// STBI_NO_PNG
// STBI_NO_BMP
// STBI_NO_PSD
// STBI_NO_TGA
// STBI_NO_GIF
// STBI_NO_HDR
// STBI_NO_PIC
// STBI_NO_PNM (.ppm and .pgm)
//
// - You can request *only* certain decoders and suppress all other ones
// (this will be more forward-compatible, as addition of new decoders
// doesn't require you to disable them explicitly):
//
// STBI_ONLY_JPEG
// STBI_ONLY_PNG
// STBI_ONLY_BMP
// STBI_ONLY_PSD
// STBI_ONLY_TGA
// STBI_ONLY_GIF
// STBI_ONLY_HDR
// STBI_ONLY_PIC
// STBI_ONLY_PNM (.ppm and .pgm)
//
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
//
// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
// than that size (in either width or height) without further processing.
// This is to let programs in the wild set an upper bound to prevent
// denial-of-service attacks on untrusted data, as one could generate a
// valid image of gigantic dimensions and force stb_image to allocate a
// huge block of memory and spend disproportionate time decoding it. By
// default this is set to (1 << 24), which is 16777216, but that's still
// very big.
#ifndef STBI_NO_STDIO
#include <stdio.h>
#endif // STBI_NO_STDIO
#define STBI_VERSION 1
enum
{
STBI_default = 0, // only used for desired_channels
STBI_grey = 1,
STBI_grey_alpha = 2,
STBI_rgb = 3,
STBI_rgb_alpha = 4
};
#include <stdlib.h>
typedef unsigned char stbi_uc;
typedef unsigned short stbi_us;
#ifdef __cplusplus
extern "C" {
#endif
#ifndef STBIDEF
#ifdef STB_IMAGE_STATIC
#define STBIDEF static
#else
#define STBIDEF extern
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// PRIMARY API - works on images of any type
//
//
// load image by filename, open file, or memory buffer
//
typedef struct
{
int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
int (*eof) (void *user); // returns nonzero if we are at end of file/data
} stbi_io_callbacks;
////////////////////////////////////
//
// 8-bits-per-channel interface
//
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
// for stbi_load_from_file, file pointer is left pointing immediately after image
#endif
#ifndef STBI_NO_GIF
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
#endif
#ifdef STBI_WINDOWS_UTF8
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif
////////////////////////////////////
//
// 16-bits-per-channel interface
//
STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
////////////////////////////////////
//
// float-per-channel interface
//
#ifndef STBI_NO_LINEAR
STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
#endif
#ifndef STBI_NO_HDR
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
STBIDEF void stbi_hdr_to_ldr_scale(float scale);
#endif // STBI_NO_HDR
#ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
STBIDEF void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_LINEAR
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
#ifndef STBI_NO_STDIO
STBIDEF int stbi_is_hdr (char const *filename);
STBIDEF int stbi_is_hdr_from_file(FILE *f);
#endif // STBI_NO_STDIO
// get a VERY brief reason for failure
// on most compilers (and ALL modern mainstream compilers) this is threadsafe
STBIDEF const char *stbi_failure_reason (void);
// free the loaded image -- this is just free()
STBIDEF void stbi_image_free (void *retval_from_stbi_load);
// get image dimensions & components without fully decoding
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
#ifndef STBI_NO_STDIO
STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit (char const *filename);
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
#endif
// for image formats that explicitly notate that they have premultiplied alpha,
// we just return the colors as stored in the file. set this flag to force
// unpremultiplication. results are undefined if the unpremultiply overflow.
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
// indicate whether we should process iphone images back to canonical format,
// or just pass them through "as-is"
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
// flip the image vertically, so the first pixel in the output array is the bottom left
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
// as above, but only applies to images loaded on the thread that calls the function
// this function is only available if your compiler supports thread-local variables;
// calling it will fail to link if your compiler doesn't
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
// ZLIB client - used by PNG, available for other purposes
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
#ifdef __cplusplus
}
#endif
//
//
//// end header file /////////////////////////////////////////////////////
#endif // STBI_INCLUDE_STB_IMAGE_H
/*
revision history:
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
1-bit BMP
*_is_16_bit api
avoid warnings
2.16 (2017-07-23) all functions have 16-bit variants;
STBI_NO_STDIO works again;
compilation fixes;
fix rounding in unpremultiply;
optimize vertical flip;
disable raw_len validation;
documentation fixes
2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
warning fixes; disable run-time SSE detection on gcc;
uniform handling of optional "return" values;
thread-safe initialization of zlib tables
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) allocate large structures on the stack
remove white matting for transparent PSD
fix reported channel count for PNG & BMP
re-enable SSE2 in non-gcc 64-bit
support RGB-formatted JPEG
read 16-bit PNGs (only as 8-bit)
2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
2.09 (2016-01-16) allow comments in PNM files
16-bit-per-pixel TGA (not bit-per-component)
info() for TGA could break due to .hdr handling
info() for BMP to shares code instead of sloppy parse
can use STBI_REALLOC_SIZED if allocator doesn't support realloc
code cleanup
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) fix compiler warnings
partial animated GIF support
limited 16-bpc PSD support
#ifdef unused functions
bug with < 92 byte PIC,PNM,HDR,TGA
2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
2.03 (2015-04-12) extra corruption checking (mmozeiko)
stbi_set_flip_vertically_on_load (nguillemot)
fix NEON support; fix mingw support
2.02 (2015-01-19) fix incorrect assert, fix warning
2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
progressive JPEG (stb)
PGM/PPM support (Ken Miller)
STBI_MALLOC,STBI_REALLOC,STBI_FREE
GIF bugfix -- seemingly never worked
STBI_NO_*, STBI_ONLY_*
1.48 (2014-12-14) fix incorrectly-named assert()
1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
optimize PNG (ryg)
fix bug in interlaced PNG with user-specified channel count (stb)
1.46 (2014-08-26)
fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
1.45 (2014-08-16)
fix MSVC-ARM internal compiler error by wrapping malloc
1.44 (2014-08-07)
various warning fixes from Ronny Chevalier
1.43 (2014-07-15)
fix MSVC-only compiler problem in code changed in 1.42
1.42 (2014-07-09)
don't define _CRT_SECURE_NO_WARNINGS (affects user code)
fixes to stbi__cleanup_jpeg path
added STBI_ASSERT to avoid requiring assert.h
1.41 (2014-06-25)
fix search&replace from 1.36 that messed up comments/error messages
1.40 (2014-06-22)
fix gcc struct-initialization warning
1.39 (2014-06-15)
fix to TGA optimization when req_comp != number of components in TGA;
fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
add support for BMP version 5 (more ignored fields)
1.38 (2014-06-06)
suppress MSVC warnings on integer casts truncating values
fix accidental rename of 'skip' field of I/O
1.37 (2014-06-04)
remove duplicate typedef
1.36 (2014-06-03)
convert to header file single-file library
if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
1.35 (2014-05-27)
various warnings
fix broken STBI_SIMD path
fix bug where stbi_load_from_file no longer left file pointer in correct place
fix broken non-easy path for 32-bit BMP (possibly never used)
TGA optimization by Arseny Kapoulkine
1.34 (unknown)
use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
1.33 (2011-07-14)
make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
1.32 (2011-07-13)
support for "info" function for all supported filetypes (SpartanJ)
1.31 (2011-06-20)
a few more leak fixes, bug in PNG handling (SpartanJ)
1.30 (2011-06-11)
added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
removed deprecated format-specific test/load functions
removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
fix inefficiency in decoding 32-bit BMP (David Woo)
1.29 (2010-08-16)
various warning fixes from Aurelien Pocheville
1.28 (2010-08-01)
fix bug in GIF palette transparency (SpartanJ)
1.27 (2010-08-01)
cast-to-stbi_uc to fix warnings
1.26 (2010-07-24)
fix bug in file buffering for PNG reported by SpartanJ
1.25 (2010-07-17)
refix trans_data warning (Won Chun)
1.24 (2010-07-12)
perf improvements reading from files on platforms with lock-heavy fgetc()
minor perf improvements for jpeg
deprecated type-specific functions so we'll get feedback if they're needed
attempt to fix trans_data warning (Won Chun)
1.23 fixed bug in iPhone support
1.22 (2010-07-10)
removed image *writing* support
stbi_info support from Jetro Lauha
GIF support from Jean-Marc Lienher
iPhone PNG-extensions from James Brown
warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
1.21 fix use of 'stbi_uc' in header (reported by jon blow)
1.20 added support for Softimage PIC, by Tom Seddon
1.19 bug in interlaced PNG corruption check (found by ryg)
1.18 (2008-08-02)
fix a threading bug (local mutable static)
1.17 support interlaced PNG
1.16 major bugfix - stbi__convert_format converted one too many pixels
1.15 initialize some fields for thread safety
1.14 fix threadsafe conversion bug
header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
1.13 threadsafe
1.12 const qualifiers in the API
1.11 Support installable IDCT, colorspace conversion routines
1.10 Fixes for 64-bit (don't use "unsigned long")
optimized upsampling by Fabian "ryg" Giesen
1.09 Fix format-conversion for PSD code (bad global variables!)
1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
1.07 attempt to fix C++ warning/errors again
1.06 attempt to fix C++ warning/errors again
1.05 fix TGA loading to return correct *comp and use good luminance calc
1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
1.02 support for (subset of) HDR files, float interface for preferred access to them
1.01 fix bug: possible bug in handling right-side up bmps... not sure
fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
1.00 interface to zlib that skips zlib header
0.99 correct handling of alpha in palette
0.98 TGA loader by lonesock; dynamically add loaders (untested)
0.97 jpeg errors on too large a file; also catch another malloc failure
0.96 fix detection of invalid v value - particleman@mollyrocket forum
0.95 during header scan, seek to markers in case of padding
0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
0.93 handle jpegtran output; verbose errors
0.92 read 4,8,16,24,32-bit BMP files of several formats
0.91 output 24-bit Windows 3.0 BMP files
0.90 fix a few more warnings; bump version number to approach 1.0
0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
0.60 fix compiling as c++
0.59 fix warnings: merge Dave Moore's -Wall fixes
0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
0.56 fix bug: zlib uncompressed mode len vs. nlen
0.55 fix bug: restart_interval not initialized to 0
0.54 allow NULL for 'int *comp'
0.53 fix bug in png 3->4; speedup png decoding
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
on 'test' only check type, not whether we support this variant
0.50 (2006-11-19)
first released version
*/
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

2282
externals/stb/stb_image_resize.cpp vendored Normal file

File diff suppressed because it is too large Load diff

426
externals/stb/stb_image_resize.h vendored Normal file
View file

@ -0,0 +1,426 @@
// SPDX-FileCopyrightText: Jorge L Rodriguez
// SPDX-License-Identifier: MIT
/* stb_image_resize - v0.97 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb
Written with emphasis on usability, portability, and efficiency. (No
SIMD or threads, so it be easily outperformed by libs that use those.)
Only scaling and translation is supported, no rotations or shears.
Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
COMPILING & LINKING
In one C/C++ file that #includes this file, do this:
#define STB_IMAGE_RESIZE_IMPLEMENTATION
before the #include. That will create the implementation in that file.
QUICKSTART
stbir_resize_uint8( input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0, num_channels)
stbir_resize_float(...)
stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0)
stbir_resize_uint8_srgb_edgemode(
input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
// WRAP/REFLECT/ZERO
FULL API
See the "header file" section of the source for API documentation.
ADDITIONAL DOCUMENTATION
SRGB & FLOATING POINT REPRESENTATION
The sRGB functions presume IEEE floating point. If you do not have
IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
a slower implementation.
MEMORY ALLOCATION
The resize functions here perform a single memory allocation using
malloc. To control the memory allocation, before the #include that
triggers the implementation, do:
#define STBIR_MALLOC(size,context) ...
#define STBIR_FREE(ptr,context) ...
Each resize function makes exactly one call to malloc/free, so to use
temp memory, store the temp memory in the context and return that.
ASSERT
Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
OPTIMIZATION
Define STBIR_SATURATE_INT to compute clamp values in-range using
integer operations instead of float operations. This may be faster
on some platforms.
DEFAULT FILTERS
For functions which don't provide explicit control over what filters
to use, you can change the compile-time defaults with
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
See stbir_filter in the header-file section for the list of filters.
NEW FILTERS
A number of 1D filter kernels are used. For a list of
supported filters see the stbir_filter enum. To add a new filter,
write a filter function and add it to stbir__filter_info_table.
PROGRESS
For interactive use with slow resize operations, you can install
a progress-report callback:
#define STBIR_PROGRESS_REPORT(val) some_func(val)
The parameter val is a float which goes from 0 to 1 as progress is made.
For example:
static void my_progress_report(float progress);
#define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
static void my_progress_report(float progress)
{
printf("Progress: %f%%\n", progress*100);
}
MAX CHANNELS
If your image has more than 64 channels, define STBIR_MAX_CHANNELS
to the max you'll have.
ALPHA CHANNEL
Most of the resizing functions provide the ability to control how
the alpha channel of an image is processed. The important things
to know about this:
1. The best mathematically-behaved version of alpha to use is
called "premultiplied alpha", in which the other color channels
have had the alpha value multiplied in. If you use premultiplied
alpha, linear filtering (such as image resampling done by this
library, or performed in texture units on GPUs) does the "right
thing". While premultiplied alpha is standard in the movie CGI
industry, it is still uncommon in the videogame/real-time world.
If you linearly filter non-premultiplied alpha, strange effects
occur. (For example, the 50/50 average of 99% transparent bright green
and 1% transparent black produces 50% transparent dark green when
non-premultiplied, whereas premultiplied it produces 50%
transparent near-black. The former introduces green energy
that doesn't exist in the source image.)
2. Artists should not edit premultiplied-alpha images; artists
want non-premultiplied alpha images. Thus, art tools generally output
non-premultiplied alpha images.
3. You will get best results in most cases by converting images
to premultiplied alpha before processing them mathematically.
4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
resizer does not do anything special for the alpha channel;
it is resampled identically to other channels. This produces
the correct results for premultiplied-alpha images, but produces
less-than-ideal results for non-premultiplied-alpha images.
5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
then the resizer weights the contribution of input pixels
based on their alpha values, or, equivalently, it multiplies
the alpha value into the color channels, resamples, then divides
by the resultant alpha value. Input pixels which have alpha=0 do
not contribute at all to output pixels unless _all_ of the input
pixels affecting that output pixel have alpha=0, in which case
the result for that pixel is the same as it would be without
STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
input images in integer formats. For input images in float format,
input pixels with alpha=0 have no effect, and output pixels
which have alpha=0 will be 0 in all channels. (For float images,
you can manually achieve the same result by adding a tiny epsilon
value to the alpha channel of every image, and then subtracting
or clamping it at the end.)
6. You can suppress the behavior described in #5 and make
all-0-alpha pixels have 0 in all channels by #defining
STBIR_NO_ALPHA_EPSILON.
7. You can separately control whether the alpha channel is
interpreted as linear or affected by the colorspace. By default
it is linear; you almost never want to apply the colorspace.
(For example, graphics hardware does not apply sRGB conversion
to the alpha channel.)
CONTRIBUTORS
Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix
Nathan Reed: warning fixes
REVISIONS
0.97 (2020-02-02) fixed warning
0.96 (2019-03-04) fixed warnings
0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings
0.93 (2017-03-03) fixed bug with certain combinations of heights
0.92 (2017-01-02) fix integer overflow on large (>2GB) images
0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
0.90 (2014-09-17) first released version
LICENSE
See end of file for license information.
TODO
Don't decode all of the image data when only processing a partial tile
Don't use full-width decode buffers when only processing a partial tile
When processing wide images, break processing into tiles so data fits in L1 cache
Installable filters?
Resize that respects alpha test coverage
(Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
*/
#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
#ifdef _MSC_VER
typedef unsigned char stbir_uint8;
typedef unsigned short stbir_uint16;
typedef unsigned int stbir_uint32;
#else
#include <stdint.h>
typedef uint8_t stbir_uint8;
typedef uint16_t stbir_uint16;
typedef uint32_t stbir_uint32;
#endif
#ifndef STBIRDEF
#ifdef STB_IMAGE_RESIZE_STATIC
#define STBIRDEF static
#else
#ifdef __cplusplus
#define STBIRDEF extern "C"
#else
#define STBIRDEF extern
#endif
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// Easy-to-use API:
//
// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
// * input_w is input image width (x-axis), input_h is input image height (y-axis)
// * stride is the offset between successive rows of image data in memory, in bytes. you can
// specify 0 to mean packed continuously in memory
// * alpha channel is treated identically to other channels.
// * colorspace is linear or sRGB as specified by function name
// * returned result is 1 for success or 0 in case of an error.
// #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
// * Memory required grows approximately linearly with input and output size, but with
// discontinuities at input_w == output_w and input_h == output_h.
// * These functions use a "default" resampling filter defined at compile time. To change the filter,
// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels);
STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels);
// The following functions interpret image data as gamma-corrected sRGB.
// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
// or otherwise provide the index of the alpha channel. Flags value
// of 0 will probably do the right thing if you're not sure what
// the flags mean.
#define STBIR_ALPHA_CHANNEL_NONE -1
// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
// use alpha-weighted resampling (effectively premultiplying, resampling,
// then unpremultiplying).
#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
// The specified alpha channel should be handled as gamma-corrected value even
// when doing sRGB operations.
#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags);
typedef enum
{
STBIR_EDGE_CLAMP = 1,
STBIR_EDGE_REFLECT = 2,
STBIR_EDGE_WRAP = 3,
STBIR_EDGE_ZERO = 4,
} stbir_edge;
// This function adds the ability to specify how requests to sample off the edge of the image are handled.
STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode);
//////////////////////////////////////////////////////////////////////////////
//
// Medium-complexity API
//
// This extends the easy-to-use API as follows:
//
// * Alpha-channel can be processed separately
// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
// * Filter can be selected explicitly
// * uint16 image type
// * sRGB colorspace available for all types
// * context parameter for passing to STBIR_MALLOC
typedef enum
{
STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
} stbir_filter;
typedef enum
{
STBIR_COLORSPACE_LINEAR,
STBIR_COLORSPACE_SRGB,
STBIR_MAX_COLORSPACES,
} stbir_colorspace;
// The following functions are all identical except for the type of the image data
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
//////////////////////////////////////////////////////////////////////////////
//
// Full-complexity API
//
// This extends the medium API as follows:
//
// * uint32 image type
// * not typesafe
// * separate filter types for each axis
// * separate edge modes for each axis
// * can specify scale explicitly for subpixel correctness
// * can specify image source tile using texture coordinates
typedef enum
{
STBIR_TYPE_UINT8 ,
STBIR_TYPE_UINT16,
STBIR_TYPE_UINT32,
STBIR_TYPE_FLOAT ,
STBIR_MAX_TYPES
} stbir_datatype;
STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context);
STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float x_scale, float y_scale,
float x_offset, float y_offset);
STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float s0, float t0, float s1, float t1);
// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
//
//
//// end header file /////////////////////////////////////////////////////
#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View file

@ -466,14 +466,18 @@ add_library(core STATIC
hle/service/caps/caps_a.h hle/service/caps/caps_a.h
hle/service/caps/caps_c.cpp hle/service/caps/caps_c.cpp
hle/service/caps/caps_c.h hle/service/caps/caps_c.h
hle/service/caps/caps_u.cpp hle/service/caps/caps_manager.cpp
hle/service/caps/caps_u.h hle/service/caps/caps_manager.h
hle/service/caps/caps_result.h
hle/service/caps/caps_sc.cpp hle/service/caps/caps_sc.cpp
hle/service/caps/caps_sc.h hle/service/caps/caps_sc.h
hle/service/caps/caps_ss.cpp hle/service/caps/caps_ss.cpp
hle/service/caps/caps_ss.h hle/service/caps/caps_ss.h
hle/service/caps/caps_su.cpp hle/service/caps/caps_su.cpp
hle/service/caps/caps_su.h hle/service/caps/caps_su.h
hle/service/caps/caps_types.h
hle/service/caps/caps_u.cpp
hle/service/caps/caps_u.h
hle/service/erpt/erpt.cpp hle/service/erpt/erpt.cpp
hle/service/erpt/erpt.h hle/service/erpt/erpt.h
hle/service/es/es.cpp hle/service/es/es.cpp

View file

@ -31,7 +31,7 @@
#include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/apm/apm_interface.h" #include "core/hle/service/apm/apm_interface.h"
#include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/caps/caps.h" #include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/ns.h"
@ -764,6 +764,66 @@ void AppletMessageQueue::OperationModeChanged() {
on_operation_mode_changed->Signal(); on_operation_mode_changed->Signal();
} }
ILockAccessor::ILockAccessor(Core::System& system_)
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &ILockAccessor::TryLock, "TryLock"},
{2, &ILockAccessor::Unlock, "Unlock"},
{3, &ILockAccessor::GetEvent, "GetEvent"},
{4,&ILockAccessor::IsLocked, "IsLocked"},
};
// clang-format on
RegisterHandlers(functions);
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
}
ILockAccessor::~ILockAccessor() = default;
void ILockAccessor::TryLock(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto return_handle = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
// TODO: When return_handle is true this function should return the lock handle
is_locked = true;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_locked);
}
void ILockAccessor::Unlock(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
is_locked = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILockAccessor::GetEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
lock_event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(lock_event->GetReadableEvent());
}
void ILockAccessor::IsLocked(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push<u8>(is_locked);
}
ICommonStateGetter::ICommonStateGetter(Core::System& system_, ICommonStateGetter::ICommonStateGetter(Core::System& system_,
std::shared_ptr<AppletMessageQueue> msg_queue_) std::shared_ptr<AppletMessageQueue> msg_queue_)
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
@ -787,7 +847,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{14, nullptr, "GetWakeupCount"}, {14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"}, {20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"}, {30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, nullptr, "GetReaderLockAccessorEx"}, {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
{32, nullptr, "GetWriterLockAccessorEx"}, {32, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"}, {40, nullptr, "GetCradleFwVersion"},
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
@ -805,7 +865,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{65, nullptr, "GetApplicationIdByContentActionName"}, {65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"}, {67, nullptr, "CancelCpuBoostMode"},
{68, nullptr, "GetBuiltInDisplayType"}, {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"}, {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"}, {91, nullptr, "GetCurrentPerformanceConfiguration"},
@ -886,6 +946,18 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown = rp.Pop<u32>();
LOG_INFO(Service_AM, "called, unknown={}", unknown);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILockAccessor>(system);
}
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called"); LOG_WARNING(Service_AM, "called");
@ -970,6 +1042,14 @@ void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
apm_sys->SetCpuBoostMode(ctx); apm_sys->SetCpuBoostMode(ctx);
} }
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto system_button{rp.PopEnum<SystemButtonType>()}; const auto system_button{rp.PopEnum<SystemButtonType>()};
@ -1493,6 +1573,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
case Applets::AppletId::MiiEdit: case Applets::AppletId::MiiEdit:
PushInShowMiiEditData(); PushInShowMiiEditData();
break; break;
case Applets::AppletId::PhotoViewer:
PushInShowAlbum();
break;
default: default:
break; break;
} }
@ -1569,6 +1652,23 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
rb.PushRaw(applet_info); rb.PushRaw(applet_info);
} }
void ILibraryAppletSelfAccessor::PushInShowAlbum() {
const Applets::CommonArguments arguments{
.arguments_version = Applets::CommonArgumentVersion::Version3,
.size = Applets::CommonArgumentSize::Version3,
.library_version = 1,
.theme_color = Applets::ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<u8> argument_data(sizeof(arguments));
std::vector<u8> settings_data{2};
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
queue_data.emplace_back(std::move(argument_data));
queue_data.emplace_back(std::move(settings_data));
}
void ILibraryAppletSelfAccessor::PushInShowCabinetData() { void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
const Applets::CommonArguments arguments{ const Applets::CommonArguments arguments{
.arguments_version = Applets::CommonArgumentVersion::Version3, .arguments_version = Applets::CommonArgumentVersion::Version3,

View file

@ -195,6 +195,23 @@ private:
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
}; };
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
public:
explicit ILockAccessor(Core::System& system_);
~ILockAccessor() override;
private:
void TryLock(HLERequestContext& ctx);
void Unlock(HLERequestContext& ctx);
void GetEvent(HLERequestContext& ctx);
void IsLocked(HLERequestContext& ctx);
bool is_locked{};
Kernel::KEvent* lock_event;
KernelHelpers::ServiceContext service_context;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public: public:
explicit ICommonStateGetter(Core::System& system_, explicit ICommonStateGetter(Core::System& system_,
@ -237,6 +254,7 @@ private:
void GetCurrentFocusState(HLERequestContext& ctx); void GetCurrentFocusState(HLERequestContext& ctx);
void RequestToAcquireSleepLock(HLERequestContext& ctx); void RequestToAcquireSleepLock(HLERequestContext& ctx);
void GetAcquiredSleepLockEvent(HLERequestContext& ctx); void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
void GetReaderLockAccessorEx(HLERequestContext& ctx);
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
void GetOperationMode(HLERequestContext& ctx); void GetOperationMode(HLERequestContext& ctx);
void GetPerformanceMode(HLERequestContext& ctx); void GetPerformanceMode(HLERequestContext& ctx);
@ -248,6 +266,7 @@ private:
void EndVrModeEx(HLERequestContext& ctx); void EndVrModeEx(HLERequestContext& ctx);
void GetDefaultDisplayResolution(HLERequestContext& ctx); void GetDefaultDisplayResolution(HLERequestContext& ctx);
void SetCpuBoostMode(HLERequestContext& ctx); void SetCpuBoostMode(HLERequestContext& ctx);
void GetBuiltInDisplayType(HLERequestContext& ctx);
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
void GetSettingsPlatformRegion(HLERequestContext& ctx); void GetSettingsPlatformRegion(HLERequestContext& ctx);
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
@ -327,6 +346,7 @@ private:
void ExitProcessAndReturn(HLERequestContext& ctx); void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx); void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void PushInShowAlbum();
void PushInShowCabinetData(); void PushInShowCabinetData();
void PushInShowMiiEditData(); void PushInShowMiiEditData();

View file

@ -28,8 +28,8 @@ public:
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
{22, nullptr, "GetHomeMenuFunctions"}, {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{23, nullptr, "GetGlobalStateController"}, {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
}; };
// clang-format on // clang-format on
@ -110,6 +110,22 @@ private:
rb.PushIpcInterface<IAppletCommonFunctions>(system); rb.PushIpcInterface<IAppletCommonFunctions>(system);
} }
void GetHomeMenuFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHomeMenuFunctions>(system);
}
void GetGlobalStateController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IGlobalStateController>(system);
}
void GetDebugFunctions(HLERequestContext& ctx) { void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called"); LOG_DEBUG(Service_AM, "called");

View file

@ -138,6 +138,10 @@ void Error::Initialize() {
CopyArgumentData(data, args->application_error); CopyArgumentData(data, args->application_error);
error_code = Result(args->application_error.error_code); error_code = Result(args->application_error.error_code);
break; break;
case ErrorAppletMode::ShowErrorPctl:
CopyArgumentData(data, args->error_record);
error_code = Decode64BitError(args->error_record.error_code_64);
break;
case ErrorAppletMode::ShowErrorRecord: case ErrorAppletMode::ShowErrorRecord:
CopyArgumentData(data, args->error_record); CopyArgumentData(data, args->error_record);
error_code = Decode64BitError(args->error_record.error_code_64); error_code = Decode64BitError(args->error_record.error_code_64);
@ -191,6 +195,7 @@ void Error::Execute() {
frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback); frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
break; break;
} }
case ErrorAppletMode::ShowErrorPctl:
case ErrorAppletMode::ShowErrorRecord: case ErrorAppletMode::ShowErrorRecord:
reporter.SaveErrorReport(title_id, error_code, reporter.SaveErrorReport(title_id, error_code,
fmt::format("{:016X}", args->error_record.posix_time)); fmt::format("{:016X}", args->error_record.posix_time));

View file

@ -4,6 +4,7 @@
#include "core/hle/service/caps/caps.h" #include "core/hle/service/caps/caps.h"
#include "core/hle/service/caps/caps_a.h" #include "core/hle/service/caps/caps_a.h"
#include "core/hle/service/caps/caps_c.h" #include "core/hle/service/caps/caps_c.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_sc.h" #include "core/hle/service/caps/caps_sc.h"
#include "core/hle/service/caps/caps_ss.h" #include "core/hle/service/caps/caps_ss.h"
#include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_su.h"
@ -15,13 +16,21 @@ namespace Service::Capture {
void LoopProcess(Core::System& system) { void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system); auto server_manager = std::make_unique<ServerManager>(system);
auto album_manager = std::make_shared<AlbumManager>();
server_manager->RegisterNamedService(
"caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager));
server_manager->RegisterNamedService(
"caps:c", std::make_shared<IAlbumControlService>(system, album_manager));
server_manager->RegisterNamedService(
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system));
server_manager->RegisterNamedService("caps:sc",
std::make_shared<IScreenShotControlService>(system));
server_manager->RegisterNamedService("caps:su",
std::make_shared<IScreenShotApplicationService>(system));
server_manager->RegisterNamedService("caps:a", std::make_shared<CAPS_A>(system));
server_manager->RegisterNamedService("caps:c", std::make_shared<CAPS_C>(system));
server_manager->RegisterNamedService("caps:u", std::make_shared<CAPS_U>(system));
server_manager->RegisterNamedService("caps:sc", std::make_shared<CAPS_SC>(system));
server_manager->RegisterNamedService("caps:ss", std::make_shared<CAPS_SS>(system));
server_manager->RegisterNamedService("caps:su", std::make_shared<CAPS_SU>(system));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

View file

@ -3,93 +3,12 @@
#pragma once #pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Core { namespace Core {
class System; class System;
} }
namespace Service::SM {
class ServiceManager;
}
namespace Service::Capture { namespace Service::Capture {
enum class AlbumImageOrientation {
Orientation0 = 0,
Orientation1 = 1,
Orientation2 = 2,
Orientation3 = 3,
};
enum class AlbumReportOption : s32 {
Disable = 0,
Enable = 1,
};
enum class ContentType : u8 {
Screenshot = 0,
Movie = 1,
ExtraMovie = 3,
};
enum class AlbumStorage : u8 {
NAND = 0,
SD = 1,
};
struct AlbumFileDateTime {
s16 year{};
s8 month{};
s8 day{};
s8 hour{};
s8 minute{};
s8 second{};
s8 uid{};
};
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
struct AlbumEntry {
u64 size{};
u64 application_id{};
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(6);
};
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
struct AlbumFileEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{1}; // Set to 1 on official SW
};
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
struct ApplicationAlbumEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{1}; // Set to 1 on official SW
};
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
struct ApplicationAlbumFileEntry {
ApplicationAlbumEntry entry{};
AlbumFileDateTime datetime{};
u64 unknown{};
};
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
"ApplicationAlbumFileEntry has incorrect size.");
void LoopProcess(Core::System& system); void LoopProcess(Core::System& system);
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -1,40 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/caps/caps_a.h" #include "core/hle/service/caps/caps_a.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture { namespace Service::Capture {
class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
public: std::shared_ptr<AlbumManager> album_manager)
explicit IAlbumAccessorSession(Core::System& system_) : ServiceFramework{system_, "caps:a"}, manager{album_manager} {
: ServiceFramework{system_, "IAlbumAccessorSession"} {
// clang-format off
static const FunctionInfo functions[] = {
{2001, nullptr, "OpenAlbumMovieReadStream"},
{2002, nullptr, "CloseAlbumMovieReadStream"},
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
{2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
{2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
{2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
};
// clang-format on
RegisterHandlers(functions);
}
};
CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "GetAlbumFileCount"}, {0, nullptr, "GetAlbumFileCount"},
{1, nullptr, "GetAlbumFileList"}, {1, nullptr, "GetAlbumFileList"},
{2, nullptr, "LoadAlbumFile"}, {2, nullptr, "LoadAlbumFile"},
{3, nullptr, "DeleteAlbumFile"}, {3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"},
{4, nullptr, "StorageCopyAlbumFile"}, {4, nullptr, "StorageCopyAlbumFile"},
{5, nullptr, "IsAlbumMounted"}, {5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"},
{6, nullptr, "GetAlbumUsage"}, {6, nullptr, "GetAlbumUsage"},
{7, nullptr, "GetAlbumFileSize"}, {7, nullptr, "GetAlbumFileSize"},
{8, nullptr, "LoadAlbumFileThumbnail"}, {8, nullptr, "LoadAlbumFileThumbnail"},
@ -47,18 +33,18 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
{15, nullptr, "GetAlbumUsage3"}, {15, nullptr, "GetAlbumUsage3"},
{16, nullptr, "GetAlbumMountResult"}, {16, nullptr, "GetAlbumMountResult"},
{17, nullptr, "GetAlbumUsage16"}, {17, nullptr, "GetAlbumUsage16"},
{18, nullptr, "Unknown18"}, {18, &IAlbumAccessorService::Unknown18, "Unknown18"},
{19, nullptr, "Unknown19"}, {19, nullptr, "Unknown19"},
{100, nullptr, "GetAlbumFileCountEx0"}, {100, nullptr, "GetAlbumFileCountEx0"},
{101, nullptr, "GetAlbumFileListEx0"}, {101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"},
{202, nullptr, "SaveEditedScreenShot"}, {202, nullptr, "SaveEditedScreenShot"},
{301, nullptr, "GetLastThumbnail"}, {301, nullptr, "GetLastThumbnail"},
{302, nullptr, "GetLastOverlayMovieThumbnail"}, {302, nullptr, "GetLastOverlayMovieThumbnail"},
{401, nullptr, "GetAutoSavingStorage"}, {401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"},
{501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
{1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"}, {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
{1002, nullptr, "LoadAlbumScreenShotImageEx1"}, {1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"},
{1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"}, {1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"},
{8001, nullptr, "ForceAlbumUnmounted"}, {8001, nullptr, "ForceAlbumUnmounted"},
{8002, nullptr, "ResetAlbumMountStatus"}, {8002, nullptr, "ResetAlbumMountStatus"},
{8011, nullptr, "RefreshAlbumCache"}, {8011, nullptr, "RefreshAlbumCache"},
@ -74,6 +60,199 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
RegisterHandlers(functions); RegisterHandlers(functions);
} }
CAPS_A::~CAPS_A() = default; IAlbumAccessorService::~IAlbumAccessorService() = default;
void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
file_id.application_id, file_id.storage, file_id.type);
Result result = manager->DeleteAlbumFile(file_id);
result = TranslateResult(result);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<AlbumStorage>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
Result result = manager->IsAlbumMounted(storage);
const bool is_mounted = result.IsSuccess();
result = TranslateResult(result);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push<u8>(is_mounted);
}
void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) {
struct UnknownBuffer {
INSERT_PADDING_BYTES(0x10);
};
static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size");
LOG_WARNING(Service_Capture, "(STUBBED) called");
std::vector<UnknownBuffer> buffer{};
if (!buffer.empty()) {
ctx.WriteBuffer(buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(buffer.size()));
}
void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<AlbumStorage>()};
const auto flags{rp.Pop<u8>()};
const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()};
LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
std::vector<AlbumEntry> entries;
Result result = manager->GetAlbumFileList(entries, storage, flags);
result = TranslateResult(result);
entries.resize(std::min(album_entry_size, entries.size()));
if (!entries.empty()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push(entries.size());
}
void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
LOG_WARNING(Service_Capture, "(STUBBED) called");
bool is_autosaving{};
Result result = manager->GetAutoSavingStorage(is_autosaving);
result = TranslateResult(result);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push<u8>(is_autosaving);
}
void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
const auto image_buffer_size{ctx.GetWriteBufferSize(1)};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
std::vector<u8> image;
LoadAlbumScreenShotImageOutput image_output;
Result result =
manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options);
result = TranslateResult(result);
if (image.size() > image_buffer_size) {
result = ResultWorkMemoryError;
}
if (result.IsSuccess()) {
ctx.WriteBuffer(image_output, 0);
ctx.WriteBuffer(image, 1);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
std::vector<u8> image(ctx.GetWriteBufferSize(1));
LoadAlbumScreenShotImageOutput image_output;
Result result =
manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options);
result = TranslateResult(result);
if (result.IsSuccess()) {
ctx.WriteBuffer(image_output, 0);
ctx.WriteBuffer(image, 1);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
Result IAlbumAccessorService::TranslateResult(Result in_result) {
if (in_result.IsSuccess()) {
return in_result;
}
if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) {
if (in_result.description - 0x514 < 100) {
return ResultInvalidFileData;
}
if (in_result.description - 0x5dc < 100) {
return ResultInvalidFileData;
}
if (in_result.description - 0x578 < 100) {
if (in_result == ResultFileCountLimit) {
return ResultUnknown22;
}
return ResultUnknown25;
}
if (in_result.raw < ResultUnknown1801.raw) {
if (in_result == ResultUnknown1202) {
return ResultUnknown810;
}
if (in_result == ResultUnknown1203) {
return ResultUnknown810;
}
if (in_result == ResultUnknown1701) {
return ResultUnknown5;
}
} else if (in_result.raw < ResultUnknown1803.raw) {
if (in_result == ResultUnknown1801) {
return ResultUnknown5;
}
if (in_result == ResultUnknown1802) {
return ResultUnknown6;
}
} else {
if (in_result == ResultUnknown1803) {
return ResultUnknown7;
}
if (in_result == ResultUnknown1804) {
return ResultOutOfRange;
}
}
return ResultUnknown1024;
}
if (in_result.module == ErrorModule::FS) {
if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) ||
(((in_result.description - 3000) >> 3) < 0x271)) {
// TODO: Translate FS error
return in_result;
}
}
return in_result;
}
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -10,11 +10,26 @@ class System;
} }
namespace Service::Capture { namespace Service::Capture {
class AlbumManager;
class CAPS_A final : public ServiceFramework<CAPS_A> { class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> {
public: public:
explicit CAPS_A(Core::System& system_); explicit IAlbumAccessorService(Core::System& system_,
~CAPS_A() override; std::shared_ptr<AlbumManager> album_manager);
~IAlbumAccessorService() override;
private:
void DeleteAlbumFile(HLERequestContext& ctx);
void IsAlbumMounted(HLERequestContext& ctx);
void Unknown18(HLERequestContext& ctx);
void GetAlbumFileListEx0(HLERequestContext& ctx);
void GetAutoSavingStorage(HLERequestContext& ctx);
void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx);
void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx);
Result TranslateResult(Result in_result);
std::shared_ptr<AlbumManager> manager = nullptr;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -3,53 +3,21 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/service/caps/caps_c.h" #include "core/hle/service/caps/caps_c.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
namespace Service::Capture { namespace Service::Capture {
class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { IAlbumControlService::IAlbumControlService(Core::System& system_,
public: std::shared_ptr<AlbumManager> album_manager)
explicit IAlbumControlSession(Core::System& system_) : ServiceFramework{system_, "caps:c"}, manager{album_manager} {
: ServiceFramework{system_, "IAlbumControlSession"} {
// clang-format off
static const FunctionInfo functions[] = {
{2001, nullptr, "OpenAlbumMovieReadStream"},
{2002, nullptr, "CloseAlbumMovieReadStream"},
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
{2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
{2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
{2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
{2401, nullptr, "OpenAlbumMovieWriteStream"},
{2402, nullptr, "FinishAlbumMovieWriteStream"},
{2403, nullptr, "CommitAlbumMovieWriteStream"},
{2404, nullptr, "DiscardAlbumMovieWriteStream"},
{2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"},
{2406, nullptr, "CommitAlbumMovieWriteStreamEx"},
{2411, nullptr, "StartAlbumMovieWriteStreamDataSection"},
{2412, nullptr, "EndAlbumMovieWriteStreamDataSection"},
{2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"},
{2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"},
{2421, nullptr, "ReadDataFromAlbumMovieWriteStream"},
{2422, nullptr, "WriteDataToAlbumMovieWriteStream"},
{2424, nullptr, "WriteMetaToAlbumMovieWriteStream"},
{2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"},
{2433, nullptr, "GetAlbumMovieWriteStreamDataSize"},
{2434, nullptr, "SetAlbumMovieWriteStreamDataSize"},
};
// clang-format on
RegisterHandlers(functions);
}
};
CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{1, nullptr, "CaptureRawImage"}, {1, nullptr, "CaptureRawImage"},
{2, nullptr, "CaptureRawImageWithTimeout"}, {2, nullptr, "CaptureRawImageWithTimeout"},
{33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"}, {33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{1001, nullptr, "RequestTakingScreenShot"}, {1001, nullptr, "RequestTakingScreenShot"},
{1002, nullptr, "RequestTakingScreenShotWithTimeout"}, {1002, nullptr, "RequestTakingScreenShotWithTimeout"},
{1011, nullptr, "NotifyTakingScreenShotRefused"}, {1011, nullptr, "NotifyTakingScreenShotRefused"},
@ -72,9 +40,9 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
RegisterHandlers(functions); RegisterHandlers(functions);
} }
CAPS_C::~CAPS_C() = default; IAlbumControlService::~IAlbumControlService() = default;
void CAPS_C::SetShimLibraryVersion(HLERequestContext& ctx) { void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()}; const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};

View file

@ -10,14 +10,18 @@ class System;
} }
namespace Service::Capture { namespace Service::Capture {
class AlbumManager;
class CAPS_C final : public ServiceFramework<CAPS_C> { class IAlbumControlService final : public ServiceFramework<IAlbumControlService> {
public: public:
explicit CAPS_C(Core::System& system_); explicit IAlbumControlService(Core::System& system_,
~CAPS_C() override; std::shared_ptr<AlbumManager> album_manager);
~IAlbumControlService() override;
private: private:
void SetShimLibraryVersion(HLERequestContext& ctx); void SetShimLibraryVersion(HLERequestContext& ctx);
std::shared_ptr<AlbumManager> manager = nullptr;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -0,0 +1,342 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <sstream>
#include <stb_image.h>
#include <stb_image_resize.h>
#include "common/fs/file.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
namespace Service::Capture {
AlbumManager::AlbumManager() {}
AlbumManager::~AlbumManager() = default;
Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) {
if (file_id.storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
std::filesystem::path path;
const auto result = GetFile(path, file_id);
if (result.IsError()) {
return result;
}
if (!Common::FS::RemoveFile(path)) {
return ResultFileNotFound;
}
return ResultSuccess;
}
Result AlbumManager::IsAlbumMounted(AlbumStorage storage) {
if (storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
is_mounted = true;
if (storage == AlbumStorage::Sd) {
FindScreenshots();
}
return is_mounted ? ResultSuccess : ResultIsNotMounted;
}
Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const {
if (storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
for (auto& [file_id, path] : album_files) {
if (file_id.storage != storage) {
continue;
}
if (out_entries.size() >= SdAlbumFileLimit) {
break;
}
const auto entry_size = Common::FS::GetSize(path);
out_entries.push_back({
.entry_size = entry_size,
.file_id = file_id,
});
}
return ResultSuccess;
}
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const {
if (!is_mounted) {
return ResultIsNotMounted;
}
for (auto& [file_id, path] : album_files) {
if (file_id.type != contex_type) {
continue;
}
if (file_id.date > start_date) {
continue;
}
if (file_id.date < end_date) {
continue;
}
if (out_entries.size() >= SdAlbumFileLimit) {
break;
}
const auto entry_size = Common::FS::GetSize(path);
ApplicationAlbumFileEntry entry{.entry =
{
.size = entry_size,
.hash{},
.datetime = file_id.date,
.storage = file_id.storage,
.content = contex_type,
.unknown = 1,
},
.datetime = file_id.date,
.unknown = {}};
out_entries.push_back(entry);
}
return ResultSuccess;
}
Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const {
out_is_autosaving = false;
return ResultSuccess;
}
Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
std::vector<u8>& out_image,
const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const {
if (file_id.storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
out_image_output = {
.width = 1280,
.height = 720,
.attribute =
{
.unknown_0{},
.orientation = AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
},
};
std::filesystem::path path;
const auto result = GetFile(path, file_id);
if (result.IsError()) {
return result;
}
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
+static_cast<int>(out_image_output.height), decoder_options.flags);
}
Result AlbumManager::LoadAlbumScreenShotThumbnail(
LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image,
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const {
if (file_id.storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
out_image_output = {
.width = 320,
.height = 180,
.attribute =
{
.unknown_0{},
.orientation = AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
},
};
std::filesystem::path path;
const auto result = GetFile(path, file_id);
if (result.IsError()) {
return result;
}
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
+static_cast<int>(out_image_output.height), decoder_options.flags);
}
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
const auto file = album_files.find(file_id);
if (file == album_files.end()) {
return ResultFileNotFound;
}
out_path = file->second;
return ResultSuccess;
}
void AlbumManager::FindScreenshots() {
is_mounted = false;
album_files.clear();
// TODO: Swap this with a blocking operation.
const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir);
Common::FS::IterateDirEntries(
screenshots_dir,
[this](const std::filesystem::path& full_path) {
AlbumEntry entry;
if (GetAlbumEntry(entry, full_path).IsError()) {
return true;
}
while (album_files.contains(entry.file_id)) {
if (++entry.file_id.date.unique_id == 0) {
break;
}
}
album_files[entry.file_id] = full_path;
return true;
},
Common::FS::DirEntryFilter::File);
is_mounted = true;
}
Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const {
std::istringstream line_stream(path.filename().string());
std::string date;
std::string application;
std::string time;
// Parse filename to obtain entry properties
std::getline(line_stream, application, '_');
std::getline(line_stream, date, '_');
std::getline(line_stream, time, '_');
std::istringstream date_stream(date);
std::istringstream time_stream(time);
std::string year;
std::string month;
std::string day;
std::string hour;
std::string minute;
std::string second;
std::getline(date_stream, year, '-');
std::getline(date_stream, month, '-');
std::getline(date_stream, day, '-');
std::getline(time_stream, hour, '-');
std::getline(time_stream, minute, '-');
std::getline(time_stream, second, '-');
try {
out_entry = {
.entry_size = 1,
.file_id{
.application_id = static_cast<u64>(std::stoll(application, 0, 16)),
.date =
{
.year = static_cast<u16>(std::stoi(year)),
.month = static_cast<u8>(std::stoi(month)),
.day = static_cast<u8>(std::stoi(day)),
.hour = static_cast<u8>(std::stoi(hour)),
.minute = static_cast<u8>(std::stoi(minute)),
.second = static_cast<u8>(std::stoi(second)),
.unique_id = 0,
},
.storage = AlbumStorage::Sd,
.type = ContentType::Screenshot,
.unknown = 1,
},
};
} catch (const std::invalid_argument&) {
return ResultUnknown;
} catch (const std::out_of_range&) {
return ResultUnknown;
} catch (const std::exception&) {
return ResultUnknown;
}
return ResultSuccess;
}
Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path,
int width, int height, ScreenShotDecoderFlag flag) const {
if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) {
return ResultUnknown;
}
const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read,
Common::FS::FileType::BinaryFile};
std::vector<u8> raw_file(db_file.GetSize());
if (db_file.Read(raw_file) != raw_file.size()) {
return ResultUnknown;
}
int filter_flag = STBIR_FILTER_DEFAULT;
int original_width, original_height, color_channels;
const auto dbi_image =
stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width,
&original_height, &color_channels, STBI_rgb_alpha);
if (dbi_image == nullptr) {
return ResultUnknown;
}
switch (flag) {
case ScreenShotDecoderFlag::EnableFancyUpsampling:
filter_flag = STBIR_FILTER_TRIANGLE;
break;
case ScreenShotDecoderFlag::EnableBlockSmoothing:
filter_flag = STBIR_FILTER_BOX;
break;
default:
filter_flag = STBIR_FILTER_DEFAULT;
break;
}
stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width,
height, 0, STBI_rgb_alpha, 3, filter_flag);
return ResultSuccess;
}
} // namespace Service::Capture

View file

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <unordered_map>
#include "common/fs/fs.h"
#include "core/hle/result.h"
#include "core/hle/service/caps/caps_types.h"
namespace Core {
class System;
}
namespace std {
// Hash used to create lists from AlbumFileId data
template <>
struct hash<Service::Capture::AlbumFileId> {
size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept {
u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8);
hash_value ^= (static_cast<u64>(pad_id.date.month) << 7);
hash_value ^= (static_cast<u64>(pad_id.date.day) << 6);
hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5);
hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4);
hash_value ^= (static_cast<u64>(pad_id.date.second) << 3);
hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2);
hash_value ^= (static_cast<u64>(pad_id.storage) << 1);
hash_value ^= static_cast<u64>(pad_id.type);
return static_cast<size_t>(hash_value);
}
};
} // namespace std
namespace Service::Capture {
class AlbumManager {
public:
explicit AlbumManager();
~AlbumManager();
Result DeleteAlbumFile(const AlbumFileId& file_id);
Result IsAlbumMounted(AlbumStorage storage);
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const;
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
std::vector<u8>& out_image, const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const;
Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output,
std::vector<u8>& out_image, const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const;
private:
static constexpr std::size_t NandAlbumFileLimit = 1000;
static constexpr std::size_t SdAlbumFileLimit = 10000;
void FindScreenshots();
Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const;
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
int height, ScreenShotDecoderFlag flag) const;
bool is_mounted{};
std::unordered_map<AlbumFileId, std::filesystem::path> album_files;
};
} // namespace Service::Capture

View file

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::Capture {
constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3);
constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12);
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);
constexpr Result ResultUnknown22(ErrorModule::Capture, 22);
constexpr Result ResultFileNotFound(ErrorModule::Capture, 23);
constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24);
constexpr Result ResultUnknown25(ErrorModule::Capture, 25);
constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30);
constexpr Result ResultUnknown810(ErrorModule::Capture, 810);
constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024);
constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202);
constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203);
constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401);
constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701);
constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801);
constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802);
constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803);
constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804);
} // namespace Service::Capture

View file

@ -5,7 +5,8 @@
namespace Service::Capture { namespace Service::Capture {
CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} { IScreenShotControlService::IScreenShotControlService(Core::System& system_)
: ServiceFramework{system_, "caps:sc"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{1, nullptr, "CaptureRawImage"}, {1, nullptr, "CaptureRawImage"},
@ -34,6 +35,6 @@ CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
RegisterHandlers(functions); RegisterHandlers(functions);
} }
CAPS_SC::~CAPS_SC() = default; IScreenShotControlService::~IScreenShotControlService() = default;
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -11,10 +11,10 @@ class System;
namespace Service::Capture { namespace Service::Capture {
class CAPS_SC final : public ServiceFramework<CAPS_SC> { class IScreenShotControlService final : public ServiceFramework<IScreenShotControlService> {
public: public:
explicit CAPS_SC(Core::System& system_); explicit IScreenShotControlService(Core::System& system_);
~CAPS_SC() override; ~IScreenShotControlService() override;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -5,7 +5,8 @@
namespace Service::Capture { namespace Service::Capture {
CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} { IScreenShotService::IScreenShotService(Core::System& system_)
: ServiceFramework{system_, "caps:ss"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{201, nullptr, "SaveScreenShot"}, {201, nullptr, "SaveScreenShot"},
@ -21,6 +22,6 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
RegisterHandlers(functions); RegisterHandlers(functions);
} }
CAPS_SS::~CAPS_SS() = default; IScreenShotService::~IScreenShotService() = default;
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -11,10 +11,10 @@ class System;
namespace Service::Capture { namespace Service::Capture {
class CAPS_SS final : public ServiceFramework<CAPS_SS> { class IScreenShotService final : public ServiceFramework<IScreenShotService> {
public: public:
explicit CAPS_SS(Core::System& system_); explicit IScreenShotService(Core::System& system_);
~CAPS_SS() override; ~IScreenShotService() override;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -7,10 +7,11 @@
namespace Service::Capture { namespace Service::Capture {
CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} { IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_)
: ServiceFramework{system_, "caps:su"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{201, nullptr, "SaveScreenShot"}, {201, nullptr, "SaveScreenShot"},
{203, nullptr, "SaveScreenShotEx0"}, {203, nullptr, "SaveScreenShotEx0"},
{205, nullptr, "SaveScreenShotEx1"}, {205, nullptr, "SaveScreenShotEx1"},
@ -21,9 +22,9 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
RegisterHandlers(functions); RegisterHandlers(functions);
} }
CAPS_SU::~CAPS_SU() = default; IScreenShotApplicationService::~IScreenShotApplicationService() = default;
void CAPS_SU::SetShimLibraryVersion(HLERequestContext& ctx) { void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()}; const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};

View file

@ -11,10 +11,10 @@ class System;
namespace Service::Capture { namespace Service::Capture {
class CAPS_SU final : public ServiceFramework<CAPS_SU> { class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
public: public:
explicit CAPS_SU(Core::System& system_); explicit IScreenShotApplicationService(Core::System& system_);
~CAPS_SU() override; ~IScreenShotApplicationService() override;
private: private:
void SetShimLibraryVersion(HLERequestContext& ctx); void SetShimLibraryVersion(HLERequestContext& ctx);

View file

@ -0,0 +1,184 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::Capture {
// This is nn::album::ImageOrientation
enum class AlbumImageOrientation {
None,
Rotate90,
Rotate180,
Rotate270,
};
// This is nn::album::AlbumReportOption
enum class AlbumReportOption : s32 {
Disable,
Enable,
};
enum class ContentType : u8 {
Screenshot = 0,
Movie = 1,
ExtraMovie = 3,
};
enum class AlbumStorage : u8 {
Nand,
Sd,
};
enum class ScreenShotDecoderFlag : u64 {
None = 0,
EnableFancyUpsampling = 1 << 0,
EnableBlockSmoothing = 1 << 1,
};
// This is nn::capsrv::AlbumFileDateTime
struct AlbumFileDateTime {
u16 year{};
u8 month{};
u8 day{};
u8 hour{};
u8 minute{};
u8 second{};
u8 unique_id{};
friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default;
friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
if (a.year > b.year) {
return true;
}
if (a.month > b.month) {
return true;
}
if (a.day > b.day) {
return true;
}
if (a.hour > b.hour) {
return true;
}
if (a.minute > b.minute) {
return true;
}
return a.second > b.second;
};
friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
if (a.year < b.year) {
return true;
}
if (a.month < b.month) {
return true;
}
if (a.day < b.day) {
return true;
}
if (a.hour < b.hour) {
return true;
}
if (a.minute < b.minute) {
return true;
}
return a.second < b.second;
};
};
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
// This is nn::album::AlbumEntry
struct AlbumFileEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{}; // Set to 1 on official SW
};
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
struct AlbumFileId {
u64 application_id{};
AlbumFileDateTime date{};
AlbumStorage storage{};
ContentType type{};
INSERT_PADDING_BYTES(0x5);
u8 unknown{};
friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default;
};
static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size");
// This is nn::capsrv::AlbumEntry
struct AlbumEntry {
u64 entry_size{};
AlbumFileId file_id{};
};
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
// This is nn::capsrv::ApplicationAlbumEntry
struct ApplicationAlbumEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{1}; // Set to 1 on official SW
};
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
// This is nn::capsrv::ApplicationAlbumFileEntry
struct ApplicationAlbumFileEntry {
ApplicationAlbumEntry entry{};
AlbumFileDateTime datetime{};
u64 unknown{};
};
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
"ApplicationAlbumFileEntry has incorrect size.");
struct ApplicationData {
std::array<u8, 0x400> data{};
u32 data_size{};
};
static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size");
struct ScreenShotAttribute {
u32 unknown_0{};
AlbumImageOrientation orientation{};
u32 unknown_1{};
u32 unknown_2{};
INSERT_PADDING_BYTES(0x30);
};
static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size");
struct ScreenShotDecodeOption {
ScreenShotDecoderFlag flags{};
INSERT_PADDING_BYTES(0x18);
};
static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size");
struct LoadAlbumScreenShotImageOutput {
s64 width{};
s64 height{};
ScreenShotAttribute attribute{};
INSERT_PADDING_BYTES(0x400);
};
static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450,
"LoadAlbumScreenShotImageOutput is an invalid size");
struct LoadAlbumScreenShotImageOutputForApplication {
s64 width{};
s64 height{};
ScreenShotAttribute attribute{};
ApplicationData data{};
INSERT_PADDING_BYTES(0xAC);
};
static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500,
"LoadAlbumScreenShotImageOutput is an invalid size");
} // namespace Service::Capture

View file

@ -2,45 +2,29 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/service/caps/caps.h" #include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/caps/caps_u.h" #include "core/hle/service/caps/caps_u.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
namespace Service::Capture { namespace Service::Capture {
class IAlbumAccessorApplicationSession final IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
: public ServiceFramework<IAlbumAccessorApplicationSession> { std::shared_ptr<AlbumManager> album_manager)
public: : ServiceFramework{system_, "caps:u"}, manager{album_manager} {
explicit IAlbumAccessorApplicationSession(Core::System& system_)
: ServiceFramework{system_, "IAlbumAccessorApplicationSession"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{2001, nullptr, "OpenAlbumMovieReadStream"}, {32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{2002, nullptr, "CloseAlbumMovieReadStream"}, {102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, {103, nullptr, "DeleteAlbumFileByAruid"},
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, {104, nullptr, "GetAlbumFileSizeByAruid"},
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
};
// clang-format on
RegisterHandlers(functions);
}
};
CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
{105, nullptr, "DeleteAlbumFileByAruidForDebug"}, {105, nullptr, "DeleteAlbumFileByAruidForDebug"},
{110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"}, {110, nullptr, "LoadAlbumScreenShotImageByAruid"},
{120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"}, {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
{130, nullptr, "PrecheckToCreateContentsForApplication"}, {130, nullptr, "PrecheckToCreateContentsByAruid"},
{140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
{142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, {142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
{143, nullptr, "GetAlbumFileList4AaeUidAruid"}, {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
{144, nullptr, "GetAllAlbumFileList3AaeAruid"}, {144, nullptr, "GetAllAlbumFileList3AaeAruid"},
{60002, nullptr, "OpenAccessorSessionForApplication"}, {60002, nullptr, "OpenAccessorSessionForApplication"},
@ -50,9 +34,9 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
RegisterHandlers(functions); RegisterHandlers(functions);
} }
CAPS_U::~CAPS_U() = default; IAlbumApplicationService::~IAlbumApplicationService() = default;
void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) { void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()}; const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
@ -64,10 +48,7 @@ void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) { void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
// output entries (which is copied to a s32 by official SW).
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto pid{rp.Pop<s32>()}; const auto pid{rp.Pop<s32>()};
const auto content_type{rp.PopEnum<ContentType>()}; const auto content_type{rp.PopEnum<ContentType>()};
@ -75,26 +56,49 @@ void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) {
const auto end_posix_time{rp.Pop<s64>()}; const auto end_posix_time{rp.Pop<s64>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
// TODO: Update this when we implement the album. LOG_WARNING(Service_Capture,
// Currently we do not have a method of accessing album entries, set this to 0 for now.
constexpr u32 total_entries_1{};
constexpr u32 total_entries_2{};
LOG_WARNING(
Service_Capture,
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
"end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}", "end_posix_time={}, applet_resource_user_id={}",
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id);
total_entries_1, total_entries_2);
// TODO: Translate posix to DateTime
std::vector<ApplicationAlbumFileEntry> entries;
const Result result =
manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id);
if (!entries.empty()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(result);
rb.Push(total_entries_1); rb.Push<u64>(entries.size());
rb.Push(total_entries_2);
} }
void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
GetAlbumContentsFileListForApplication(ctx); IPC::RequestParser rp{ctx};
const auto pid{rp.Pop<s32>()};
const auto content_type{rp.PopEnum<ContentType>()};
const auto start_date_time{rp.PopRaw<AlbumFileDateTime>()};
const auto end_date_time{rp.PopRaw<AlbumFileDateTime>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_Capture,
"(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid,
content_type, applet_resource_user_id);
std::vector<ApplicationAlbumFileEntry> entries;
const Result result = manager->GetAlbumFileList(entries, content_type, start_date_time,
end_date_time, applet_resource_user_id);
if (!entries.empty()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
rb.Push<u64>(entries.size());
} }
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -10,16 +10,20 @@ class System;
} }
namespace Service::Capture { namespace Service::Capture {
class AlbumManager;
class CAPS_U final : public ServiceFramework<CAPS_U> { class IAlbumApplicationService final : public ServiceFramework<IAlbumApplicationService> {
public: public:
explicit CAPS_U(Core::System& system_); explicit IAlbumApplicationService(Core::System& system_,
~CAPS_U() override; std::shared_ptr<AlbumManager> album_manager);
~IAlbumApplicationService() override;
private: private:
void SetShimLibraryVersion(HLERequestContext& ctx); void SetShimLibraryVersion(HLERequestContext& ctx);
void GetAlbumContentsFileListForApplication(HLERequestContext& ctx); void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx);
void GetAlbumFileList3AaeAruid(HLERequestContext& ctx); void GetAlbumFileList3AaeAruid(HLERequestContext& ctx);
std::shared_ptr<AlbumManager> manager = nullptr;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -545,6 +545,16 @@ void IGeneralService::IsAnyInternetRequestAccepted(HLERequestContext& ctx) {
} }
} }
void IGeneralService::IsAnyForegroundRequestAccepted(HLERequestContext& ctx) {
const bool is_accepted{};
LOG_WARNING(Service_NIFM, "(STUBBED) called, is_accepted={}", is_accepted);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_accepted);
}
IGeneralService::IGeneralService(Core::System& system_) IGeneralService::IGeneralService(Core::System& system_)
: ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} { : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
// clang-format off // clang-format off
@ -569,7 +579,7 @@ IGeneralService::IGeneralService(Core::System& system_)
{19, nullptr, "SetEthernetCommunicationEnabled"}, {19, nullptr, "SetEthernetCommunicationEnabled"},
{20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"}, {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
{21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"}, {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
{22, nullptr, "IsAnyForegroundRequestAccepted"}, {22, &IGeneralService::IsAnyForegroundRequestAccepted, "IsAnyForegroundRequestAccepted"},
{23, nullptr, "PutToSleep"}, {23, nullptr, "PutToSleep"},
{24, nullptr, "WakeUp"}, {24, nullptr, "WakeUp"},
{25, nullptr, "GetSsidListVersion"}, {25, nullptr, "GetSsidListVersion"},

View file

@ -35,6 +35,7 @@ private:
void GetInternetConnectionStatus(HLERequestContext& ctx); void GetInternetConnectionStatus(HLERequestContext& ctx);
void IsEthernetCommunicationEnabled(HLERequestContext& ctx); void IsEthernetCommunicationEnabled(HLERequestContext& ctx);
void IsAnyInternetRequestAccepted(HLERequestContext& ctx); void IsAnyInternetRequestAccepted(HLERequestContext& ctx);
void IsAnyForegroundRequestAccepted(HLERequestContext& ctx);
Network::RoomNetwork& network; Network::RoomNetwork& network;
}; };

View file

@ -7,6 +7,7 @@
#include "core/file_sys/control_metadata.h" #include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs.h" #include "core/file_sys/vfs.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/errors.h" #include "core/hle/service/ns/errors.h"
@ -502,8 +503,8 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"}, {11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"}, {43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"}, {47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"}, {48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"}, {600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"}, {601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
@ -516,6 +517,28 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
IContentManagementInterface::~IContentManagementInterface() = default; IContentManagementInterface::~IContentManagementInterface() = default;
void IContentManagementInterface::GetTotalSpaceSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<FileSys::StorageId>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetFileSystemController().GetTotalSpaceSize(storage));
}
void IContentManagementInterface::GetFreeSpaceSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<FileSys::StorageId>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetFileSystemController().GetFreeSpaceSize(storage));
}
IDocumentInterface::IDocumentInterface(Core::System& system_) IDocumentInterface::IDocumentInterface(Core::System& system_)
: ServiceFramework{system_, "IDocumentInterface"} { : ServiceFramework{system_, "IDocumentInterface"} {
// clang-format off // clang-format off

View file

@ -48,6 +48,10 @@ class IContentManagementInterface final : public ServiceFramework<IContentManage
public: public:
explicit IContentManagementInterface(Core::System& system_); explicit IContentManagementInterface(Core::System& system_);
~IContentManagementInterface() override; ~IContentManagementInterface() override;
private:
void GetTotalSpaceSize(HLERequestContext& ctx);
void GetFreeSpaceSize(HLERequestContext& ctx);
}; };
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {

View file

@ -33,7 +33,7 @@ public:
{1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
{1002, nullptr, "ConfirmLaunchApplicationPermission"}, {1002, nullptr, "ConfirmLaunchApplicationPermission"},
{1003, nullptr, "ConfirmResumeApplicationPermission"}, {1003, nullptr, "ConfirmResumeApplicationPermission"},
{1004, nullptr, "ConfirmSnsPostPermission"}, {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
{1005, nullptr, "ConfirmSystemSettingsPermission"}, {1005, nullptr, "ConfirmSystemSettingsPermission"},
{1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"}, {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
{1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
@ -236,6 +236,13 @@ private:
states.free_communication = true; states.free_communication = true;
} }
void ConfirmSnsPostPermission(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(Error::ResultNoFreeCommunication);
}
void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) { void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
const bool is_temporary_unlocked = false; const bool is_temporary_unlocked = false;

View file

@ -1560,6 +1560,7 @@ void GMainWindow::ConnectMenuEvents() {
// Tools // Tools
connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
ReinitializeKeyBehavior::Warning)); ReinitializeKeyBehavior::Warning));
connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum);
connect_menu(ui->action_Load_Cabinet_Nickname_Owner, connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); }); [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
connect_menu(ui->action_Load_Cabinet_Eraser, connect_menu(ui->action_Load_Cabinet_Eraser,
@ -1597,6 +1598,7 @@ void GMainWindow::UpdateMenuState() {
}; };
const std::array applet_actions{ const std::array applet_actions{
ui->action_Load_Album,
ui->action_Load_Cabinet_Nickname_Owner, ui->action_Load_Cabinet_Nickname_Owner,
ui->action_Load_Cabinet_Eraser, ui->action_Load_Cabinet_Eraser,
ui->action_Load_Cabinet_Restorer, ui->action_Load_Cabinet_Restorer,
@ -4224,6 +4226,29 @@ void GMainWindow::OnToggleStatusBar() {
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
} }
void GMainWindow::OnAlbum() {
constexpr u64 AlbumId = 0x010000000000100Dull;
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install the firmware to use the Album applet."));
return;
}
auto album_nca = bis_system->GetEntry(AlbumId, FileSys::ContentRecordType::Program);
if (!album_nca) {
QMessageBox::warning(this, tr("Album Applet"),
tr("Album applet is not available. Please reinstall firmware."));
return;
}
system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer);
const auto filename = QString::fromStdString(album_nca->GetFullPath());
UISettings::values.roms_path = QFileInfo(filename).path();
BootGame(filename);
}
void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
constexpr u64 CabinetId = 0x0100000000001002ull; constexpr u64 CabinetId = 0x0100000000001002ull;
auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); auto bis_system = system->GetFileSystemController().GetSystemNANDContents();

View file

@ -374,6 +374,7 @@ private slots:
void ResetWindowSize720(); void ResetWindowSize720();
void ResetWindowSize900(); void ResetWindowSize900();
void ResetWindowSize1080(); void ResetWindowSize1080();
void OnAlbum();
void OnCabinet(Service::NFP::CabinetMode mode); void OnCabinet(Service::NFP::CabinetMode mode);
void OnMiiEdit(); void OnMiiEdit();
void OnCaptureScreenshot(); void OnCaptureScreenshot();

View file

@ -160,6 +160,7 @@
<addaction name="action_Verify_installed_contents"/> <addaction name="action_Verify_installed_contents"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="menu_cabinet_applet"/> <addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/>
<addaction name="action_Load_Mii_Edit"/> <addaction name="action_Load_Mii_Edit"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="action_Capture_Screenshot"/> <addaction name="action_Capture_Screenshot"/>
@ -380,6 +381,11 @@
<string>&amp;Capture Screenshot</string> <string>&amp;Capture Screenshot</string>
</property> </property>
</action> </action>
<action name="action_Load_Album">
<property name="text">
<string>Open &amp;Album</string>
</property>
</action>
<action name="action_Load_Cabinet_Nickname_Owner"> <action name="action_Load_Cabinet_Nickname_Owner">
<property name="text"> <property name="text">
<string>&amp;Set Nickname and Owner</string> <string>&amp;Set Nickname and Owner</string>