Merge pull request #11650 from german77/lle_album
service: am: Add support for LLE Album Applet
This commit is contained in:
commit
8151a4d301
|
@ -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)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>()};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>()};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{2001, nullptr, "OpenAlbumMovieReadStream"},
|
|
||||||
{2002, nullptr, "CloseAlbumMovieReadStream"},
|
|
||||||
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
|
|
||||||
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
|
|
||||||
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
{32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||||
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
|
{102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
|
||||||
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
|
{103, nullptr, "DeleteAlbumFileByAruid"},
|
||||||
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
|
{104, nullptr, "GetAlbumFileSizeByAruid"},
|
||||||
{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.
|
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
|
||||||
constexpr u32 total_entries_1{};
|
"end_posix_time={}, applet_resource_user_id={}",
|
||||||
constexpr u32 total_entries_2{};
|
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id);
|
||||||
|
|
||||||
LOG_WARNING(
|
// TODO: Translate posix to DateTime
|
||||||
Service_Capture,
|
|
||||||
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
|
std::vector<ApplicationAlbumFileEntry> entries;
|
||||||
"end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
|
const Result result =
|
||||||
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
|
manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id);
|
||||||
total_entries_1, total_entries_2);
|
|
||||||
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"},
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>&Capture Screenshot</string>
|
<string>&Capture Screenshot</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_Load_Album">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open &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>&Set Nickname and Owner</string>
|
<string>&Set Nickname and Owner</string>
|
||||||
|
|
Loading…
Reference in New Issue