Merge pull request #11650 from german77/lle_album
service: am: Add support for LLE Album Applet
This commit is contained in:
		
							
								
								
									
										2
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -168,7 +168,7 @@ if (NOT TARGET LLVM::Demangle) | ||||
|     add_library(LLVM::Demangle ALIAS demangle) | ||||
| 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) | ||||
|  | ||||
| add_library(bc_decoder bc_decoder/bc_decoder.cpp) | ||||
|   | ||||
							
								
								
									
										7529
									
								
								externals/stb/stb_image.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7529
									
								
								externals/stb/stb_image.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										772
									
								
								externals/stb/stb_image.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										772
									
								
								externals/stb/stb_image.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,772 @@ | ||||
| // SPDX-FileCopyrightText: stb http://nothings.org/stb | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| /* stb_image - v2.28 - public domain image loader - http://nothings.org/stb | ||||
|                                   no warranty implied; use at your own risk | ||||
|  | ||||
|    Do this: | ||||
|       #define STB_IMAGE_IMPLEMENTATION | ||||
|    before you include this file in *one* C or C++ file to create the implementation. | ||||
|  | ||||
|    // i.e. it should look like this: | ||||
|    #include ... | ||||
|    #include ... | ||||
|    #include ... | ||||
|    #define STB_IMAGE_IMPLEMENTATION | ||||
|    #include "stb_image.h" | ||||
|  | ||||
|    You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. | ||||
|    And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free | ||||
|  | ||||
|  | ||||
|    QUICK NOTES: | ||||
|       Primarily of interest to game developers and other people who can | ||||
|           avoid problematic images and only need the trivial interface | ||||
|  | ||||
|       JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) | ||||
|       PNG 1/2/4/8/16-bit-per-channel | ||||
|  | ||||
|       TGA (not sure what subset, if a subset) | ||||
|       BMP non-1bpp, non-RLE | ||||
|       PSD (composited view only, no extra channels, 8/16 bit-per-channel) | ||||
|  | ||||
|       GIF (*comp always reports as 4-channel) | ||||
|       HDR (radiance rgbE format) | ||||
|       PIC (Softimage PIC) | ||||
|       PNM (PPM and PGM binary only) | ||||
|  | ||||
|       Animated GIF still needs a proper API, but here's one way to do it: | ||||
|           http://gist.github.com/urraka/685d9a6340b26b830d49 | ||||
|  | ||||
|       - decode from memory or through FILE (define STBI_NO_STDIO to remove code) | ||||
|       - decode from arbitrary I/O callbacks | ||||
|       - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) | ||||
|  | ||||
|    Full documentation under "DOCUMENTATION" below. | ||||
|  | ||||
|  | ||||
| LICENSE | ||||
|  | ||||
|   See end of file for license information. | ||||
|  | ||||
| RECENT REVISION HISTORY: | ||||
|  | ||||
|       2.28  (2023-01-29) many error fixes, security errors, just tons of stuff | ||||
|       2.27  (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes | ||||
|       2.26  (2020-07-13) many minor fixes | ||||
|       2.25  (2020-02-02) fix warnings | ||||
|       2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically | ||||
|       2.23  (2019-08-11) fix clang static analysis warning | ||||
|       2.22  (2019-03-04) gif fixes, fix warnings | ||||
|       2.21  (2019-02-25) fix typo in comment | ||||
|       2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs | ||||
|       2.19  (2018-02-11) fix warning | ||||
|       2.18  (2018-01-30) fix warnings | ||||
|       2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings | ||||
|       2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes | ||||
|       2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC | ||||
|       2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs | ||||
|       2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes | ||||
|       2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes | ||||
|       2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 | ||||
|                          RGB-format JPEG; remove white matting in PSD; | ||||
|                          allocate large structures on the stack; | ||||
|                          correct channel count for PNG & BMP | ||||
|       2.10  (2016-01-22) avoid warning introduced in 2.09 | ||||
|       2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED | ||||
|  | ||||
|    See end of file for full revision history. | ||||
|  | ||||
|  | ||||
|  ============================    Contributors    ========================= | ||||
|  | ||||
|  Image formats                          Extensions, features | ||||
|     Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info) | ||||
|     Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info) | ||||
|     Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG) | ||||
|     Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks) | ||||
|     Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG) | ||||
|     Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip) | ||||
|     Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD) | ||||
|     github:urraka (animated gif)           Junggon Kim (PNM comments) | ||||
|     Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA) | ||||
|                                            socks-the-fox (16-bit PNG) | ||||
|                                            Jeremy Sawicki (handle all ImageNet JPGs) | ||||
|  Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP) | ||||
|     Fabian "ryg" Giesen                    Anael Seghezzi (is-16-bit query) | ||||
|     Arseny Kapoulkine                      Simon Breuss (16-bit PNM) | ||||
|     John-Mark Allen | ||||
|     Carmelo J Fdez-Aguera | ||||
|  | ||||
|  Bug & warning fixes | ||||
|     Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko | ||||
|     Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski | ||||
|     Phil Jordan                                Dave Moore           Roy Eltham | ||||
|     Hayaki Saito            Nathan Reed        Won Chun | ||||
|     Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community | ||||
|     Thomas Ruf              Ronny Chevalier                         github:rlyeh | ||||
|     Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou | ||||
|     Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk | ||||
|     Eugene Golushkov        Laurent Gomila     Cort Stratton        github:snagar | ||||
|     Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex | ||||
|     Cass Everitt            Ryamond Barbiero                        github:grim210 | ||||
|     Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw | ||||
|     Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus | ||||
|     Josh Tobin              Neil Bickford      Matthew Gregan       github:poppolopoppo | ||||
|     Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji | ||||
|     Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007 | ||||
|                             Brad Weinberger    Matvey Cherevko      github:mosra | ||||
|     Luca Sas                Alexander Veselov  Zack Middleton       [reserved] | ||||
|     Ryan C. Gordon          [reserved]                              [reserved] | ||||
|                      DO NOT ADD YOUR NAME HERE | ||||
|  | ||||
|                      Jacko Dirks | ||||
|  | ||||
|   To add your name to the credits, pick a random blank space in the middle and fill it. | ||||
|   80% of merge conflicts on stb PRs are due to people adding their name at the end | ||||
|   of the credits. | ||||
| */ | ||||
|  | ||||
| #ifndef STBI_INCLUDE_STB_IMAGE_H | ||||
| #define STBI_INCLUDE_STB_IMAGE_H | ||||
|  | ||||
| // DOCUMENTATION | ||||
| // | ||||
| // Limitations: | ||||
| //    - no 12-bit-per-channel JPEG | ||||
| //    - no JPEGs with arithmetic coding | ||||
| //    - GIF always returns *comp=4 | ||||
| // | ||||
| // Basic usage (see HDR discussion below for HDR usage): | ||||
| //    int x,y,n; | ||||
| //    unsigned char *data = stbi_load(filename, &x, &y, &n, 0); | ||||
| //    // ... process data if not NULL ... | ||||
| //    // ... x = width, y = height, n = # 8-bit components per pixel ... | ||||
| //    // ... replace '0' with '1'..'4' to force that many components per pixel | ||||
| //    // ... but 'n' will always be the number that it would have been if you said 0 | ||||
| //    stbi_image_free(data); | ||||
| // | ||||
| // Standard parameters: | ||||
| //    int *x                 -- outputs image width in pixels | ||||
| //    int *y                 -- outputs image height in pixels | ||||
| //    int *channels_in_file  -- outputs # of image components in image file | ||||
| //    int desired_channels   -- if non-zero, # of image components requested in result | ||||
| // | ||||
| // The return value from an image loader is an 'unsigned char *' which points | ||||
| // to the pixel data, or NULL on an allocation failure or if the image is | ||||
| // corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, | ||||
| // with each pixel consisting of N interleaved 8-bit components; the first | ||||
| // pixel pointed to is top-left-most in the image. There is no padding between | ||||
| // image scanlines or between pixels, regardless of format. The number of | ||||
| // components N is 'desired_channels' if desired_channels is non-zero, or | ||||
| // *channels_in_file otherwise. If desired_channels is non-zero, | ||||
| // *channels_in_file has the number of components that _would_ have been | ||||
| // output otherwise. E.g. if you set desired_channels to 4, you will always | ||||
| // get RGBA output, but you can check *channels_in_file to see if it's trivially | ||||
| // opaque because e.g. there were only 3 channels in the source image. | ||||
| // | ||||
| // An output image with N components has the following components interleaved | ||||
| // in this order in each pixel: | ||||
| // | ||||
| //     N=#comp     components | ||||
| //       1           grey | ||||
| //       2           grey, alpha | ||||
| //       3           red, green, blue | ||||
| //       4           red, green, blue, alpha | ||||
| // | ||||
| // If image loading fails for any reason, the return value will be NULL, | ||||
| // and *x, *y, *channels_in_file will be unchanged. The function | ||||
| // stbi_failure_reason() can be queried for an extremely brief, end-user | ||||
| // unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS | ||||
| // to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly | ||||
| // more user-friendly ones. | ||||
| // | ||||
| // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. | ||||
| // | ||||
| // To query the width, height and component count of an image without having to | ||||
| // decode the full file, you can use the stbi_info family of functions: | ||||
| // | ||||
| //   int x,y,n,ok; | ||||
| //   ok = stbi_info(filename, &x, &y, &n); | ||||
| //   // returns ok=1 and sets x, y, n if image is a supported format, | ||||
| //   // 0 otherwise. | ||||
| // | ||||
| // Note that stb_image pervasively uses ints in its public API for sizes, | ||||
| // including sizes of memory buffers. This is now part of the API and thus | ||||
| // hard to change without causing breakage. As a result, the various image | ||||
| // loaders all have certain limits on image size; these differ somewhat | ||||
| // by format but generally boil down to either just under 2GB or just under | ||||
| // 1GB. When the decoded image would be larger than this, stb_image decoding | ||||
| // will fail. | ||||
| // | ||||
| // Additionally, stb_image will reject image files that have any of their | ||||
| // dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, | ||||
| // which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, | ||||
| // the only way to have an image with such dimensions load correctly | ||||
| // is for it to have a rather extreme aspect ratio. Either way, the | ||||
| // assumption here is that such larger images are likely to be malformed | ||||
| // or malicious. If you do need to load an image with individual dimensions | ||||
| // larger than that, and it still fits in the overall size limit, you can | ||||
| // #define STBI_MAX_DIMENSIONS on your own to be something larger. | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // UNICODE: | ||||
| // | ||||
| //   If compiling for Windows and you wish to use Unicode filenames, compile | ||||
| //   with | ||||
| //       #define STBI_WINDOWS_UTF8 | ||||
| //   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert | ||||
| //   Windows wchar_t filenames to utf8. | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // Philosophy | ||||
| // | ||||
| // stb libraries are designed with the following priorities: | ||||
| // | ||||
| //    1. easy to use | ||||
| //    2. easy to maintain | ||||
| //    3. good performance | ||||
| // | ||||
| // Sometimes I let "good performance" creep up in priority over "easy to maintain", | ||||
| // and for best performance I may provide less-easy-to-use APIs that give higher | ||||
| // performance, in addition to the easy-to-use ones. Nevertheless, it's important | ||||
| // to keep in mind that from the standpoint of you, a client of this library, | ||||
| // all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. | ||||
| // | ||||
| // Some secondary priorities arise directly from the first two, some of which | ||||
| // provide more explicit reasons why performance can't be emphasized. | ||||
| // | ||||
| //    - Portable ("ease of use") | ||||
| //    - Small source code footprint ("easy to maintain") | ||||
| //    - No dependencies ("ease of use") | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // I/O callbacks | ||||
| // | ||||
| // I/O callbacks allow you to read from arbitrary sources, like packaged | ||||
| // files or some other source. Data read from callbacks are processed | ||||
| // through a small internal buffer (currently 128 bytes) to try to reduce | ||||
| // overhead. | ||||
| // | ||||
| // The three functions you must define are "read" (reads some bytes of data), | ||||
| // "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // SIMD support | ||||
| // | ||||
| // The JPEG decoder will try to automatically use SIMD kernels on x86 when | ||||
| // supported by the compiler. For ARM Neon support, you must explicitly | ||||
| // request it. | ||||
| // | ||||
| // (The old do-it-yourself SIMD API is no longer supported in the current | ||||
| // code.) | ||||
| // | ||||
| // On x86, SSE2 will automatically be used when available based on a run-time | ||||
| // test; if not, the generic C versions are used as a fall-back. On ARM targets, | ||||
| // the typical path is to have separate builds for NEON and non-NEON devices | ||||
| // (at least this is true for iOS and Android). Therefore, the NEON support is | ||||
| // toggled by a build flag: define STBI_NEON to get NEON loops. | ||||
| // | ||||
| // If for some reason you do not want to use any of SIMD code, or if | ||||
| // you have issues compiling it, you can disable it entirely by | ||||
| // defining STBI_NO_SIMD. | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // HDR image support   (disable by defining STBI_NO_HDR) | ||||
| // | ||||
| // stb_image supports loading HDR images in general, and currently the Radiance | ||||
| // .HDR file format specifically. You can still load any file through the existing | ||||
| // interface; if you attempt to load an HDR file, it will be automatically remapped | ||||
| // to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; | ||||
| // both of these constants can be reconfigured through this interface: | ||||
| // | ||||
| //     stbi_hdr_to_ldr_gamma(2.2f); | ||||
| //     stbi_hdr_to_ldr_scale(1.0f); | ||||
| // | ||||
| // (note, do not use _inverse_ constants; stbi_image will invert them | ||||
| // appropriately). | ||||
| // | ||||
| // Additionally, there is a new, parallel interface for loading files as | ||||
| // (linear) floats to preserve the full dynamic range: | ||||
| // | ||||
| //    float *data = stbi_loadf(filename, &x, &y, &n, 0); | ||||
| // | ||||
| // If you load LDR images through this interface, those images will | ||||
| // be promoted to floating point values, run through the inverse of | ||||
| // constants corresponding to the above: | ||||
| // | ||||
| //     stbi_ldr_to_hdr_scale(1.0f); | ||||
| //     stbi_ldr_to_hdr_gamma(2.2f); | ||||
| // | ||||
| // Finally, given a filename (or an open file or memory block--see header | ||||
| // file for details) containing image data, you can query for the "most | ||||
| // appropriate" interface to use (that is, whether the image is HDR or | ||||
| // not), using: | ||||
| // | ||||
| //     stbi_is_hdr(char *filename); | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // iPhone PNG support: | ||||
| // | ||||
| // We optionally support converting iPhone-formatted PNGs (which store | ||||
| // premultiplied BGRA) back to RGB, even though they're internally encoded | ||||
| // differently. To enable this conversion, call | ||||
| // stbi_convert_iphone_png_to_rgb(1). | ||||
| // | ||||
| // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per | ||||
| // pixel to remove any premultiplied alpha *only* if the image file explicitly | ||||
| // says there's premultiplied data (currently only happens in iPhone images, | ||||
| // and only if iPhone convert-to-rgb processing is on). | ||||
| // | ||||
| // =========================================================================== | ||||
| // | ||||
| // ADDITIONAL CONFIGURATION | ||||
| // | ||||
| //  - You can suppress implementation of any of the decoders to reduce | ||||
| //    your code footprint by #defining one or more of the following | ||||
| //    symbols before creating the implementation. | ||||
| // | ||||
| //        STBI_NO_JPEG | ||||
| //        STBI_NO_PNG | ||||
| //        STBI_NO_BMP | ||||
| //        STBI_NO_PSD | ||||
| //        STBI_NO_TGA | ||||
| //        STBI_NO_GIF | ||||
| //        STBI_NO_HDR | ||||
| //        STBI_NO_PIC | ||||
| //        STBI_NO_PNM   (.ppm and .pgm) | ||||
| // | ||||
| //  - You can request *only* certain decoders and suppress all other ones | ||||
| //    (this will be more forward-compatible, as addition of new decoders | ||||
| //    doesn't require you to disable them explicitly): | ||||
| // | ||||
| //        STBI_ONLY_JPEG | ||||
| //        STBI_ONLY_PNG | ||||
| //        STBI_ONLY_BMP | ||||
| //        STBI_ONLY_PSD | ||||
| //        STBI_ONLY_TGA | ||||
| //        STBI_ONLY_GIF | ||||
| //        STBI_ONLY_HDR | ||||
| //        STBI_ONLY_PIC | ||||
| //        STBI_ONLY_PNM   (.ppm and .pgm) | ||||
| // | ||||
| //   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still | ||||
| //     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB | ||||
| // | ||||
| //  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater | ||||
| //    than that size (in either width or height) without further processing. | ||||
| //    This is to let programs in the wild set an upper bound to prevent | ||||
| //    denial-of-service attacks on untrusted data, as one could generate a | ||||
| //    valid image of gigantic dimensions and force stb_image to allocate a | ||||
| //    huge block of memory and spend disproportionate time decoding it. By | ||||
| //    default this is set to (1 << 24), which is 16777216, but that's still | ||||
| //    very big. | ||||
|  | ||||
| #ifndef STBI_NO_STDIO | ||||
| #include <stdio.h> | ||||
| #endif // STBI_NO_STDIO | ||||
|  | ||||
| #define STBI_VERSION 1 | ||||
|  | ||||
| enum | ||||
| { | ||||
|    STBI_default = 0, // only used for desired_channels | ||||
|  | ||||
|    STBI_grey       = 1, | ||||
|    STBI_grey_alpha = 2, | ||||
|    STBI_rgb        = 3, | ||||
|    STBI_rgb_alpha  = 4 | ||||
| }; | ||||
|  | ||||
| #include <stdlib.h> | ||||
| typedef unsigned char stbi_uc; | ||||
| typedef unsigned short stbi_us; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #ifndef STBIDEF | ||||
| #ifdef STB_IMAGE_STATIC | ||||
| #define STBIDEF static | ||||
| #else | ||||
| #define STBIDEF extern | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // PRIMARY API - works on images of any type | ||||
| // | ||||
|  | ||||
| // | ||||
| // load image by filename, open file, or memory buffer | ||||
| // | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|    int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read | ||||
|    void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative | ||||
|    int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data | ||||
| } stbi_io_callbacks; | ||||
|  | ||||
| //////////////////////////////////// | ||||
| // | ||||
| // 8-bits-per-channel interface | ||||
| // | ||||
|  | ||||
| STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels); | ||||
| STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
|  | ||||
| #ifndef STBI_NO_STDIO | ||||
| STBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
| STBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
| // for stbi_load_from_file, file pointer is left pointing immediately after image | ||||
| #endif | ||||
|  | ||||
| #ifndef STBI_NO_GIF | ||||
| STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); | ||||
| #endif | ||||
|  | ||||
| #ifdef STBI_WINDOWS_UTF8 | ||||
| STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); | ||||
| #endif | ||||
|  | ||||
| //////////////////////////////////// | ||||
| // | ||||
| // 16-bits-per-channel interface | ||||
| // | ||||
|  | ||||
| STBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
| STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
|  | ||||
| #ifndef STBI_NO_STDIO | ||||
| STBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
| STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
| #endif | ||||
|  | ||||
| //////////////////////////////////// | ||||
| // | ||||
| // float-per-channel interface | ||||
| // | ||||
| #ifndef STBI_NO_LINEAR | ||||
|    STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
|    STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels); | ||||
|  | ||||
|    #ifndef STBI_NO_STDIO | ||||
|    STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
|    STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); | ||||
|    #endif | ||||
| #endif | ||||
|  | ||||
| #ifndef STBI_NO_HDR | ||||
|    STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma); | ||||
|    STBIDEF void   stbi_hdr_to_ldr_scale(float scale); | ||||
| #endif // STBI_NO_HDR | ||||
|  | ||||
| #ifndef STBI_NO_LINEAR | ||||
|    STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma); | ||||
|    STBIDEF void   stbi_ldr_to_hdr_scale(float scale); | ||||
| #endif // STBI_NO_LINEAR | ||||
|  | ||||
| // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR | ||||
| STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); | ||||
| STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); | ||||
| #ifndef STBI_NO_STDIO | ||||
| STBIDEF int      stbi_is_hdr          (char const *filename); | ||||
| STBIDEF int      stbi_is_hdr_from_file(FILE *f); | ||||
| #endif // STBI_NO_STDIO | ||||
|  | ||||
|  | ||||
| // get a VERY brief reason for failure | ||||
| // on most compilers (and ALL modern mainstream compilers) this is threadsafe | ||||
| STBIDEF const char *stbi_failure_reason  (void); | ||||
|  | ||||
| // free the loaded image -- this is just free() | ||||
| STBIDEF void     stbi_image_free      (void *retval_from_stbi_load); | ||||
|  | ||||
| // get image dimensions & components without fully decoding | ||||
| STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); | ||||
| STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); | ||||
| STBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); | ||||
| STBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); | ||||
|  | ||||
| #ifndef STBI_NO_STDIO | ||||
| STBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp); | ||||
| STBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp); | ||||
| STBIDEF int      stbi_is_16_bit          (char const *filename); | ||||
| STBIDEF int      stbi_is_16_bit_from_file(FILE *f); | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
| // for image formats that explicitly notate that they have premultiplied alpha, | ||||
| // we just return the colors as stored in the file. set this flag to force | ||||
| // unpremultiplication. results are undefined if the unpremultiply overflow. | ||||
| STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); | ||||
|  | ||||
| // indicate whether we should process iphone images back to canonical format, | ||||
| // or just pass them through "as-is" | ||||
| STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); | ||||
|  | ||||
| // flip the image vertically, so the first pixel in the output array is the bottom left | ||||
| STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); | ||||
|  | ||||
| // as above, but only applies to images loaded on the thread that calls the function | ||||
| // this function is only available if your compiler supports thread-local variables; | ||||
| // calling it will fail to link if your compiler doesn't | ||||
| STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); | ||||
| STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); | ||||
| STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); | ||||
|  | ||||
| // ZLIB client - used by PNG, available for other purposes | ||||
|  | ||||
| STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); | ||||
| STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); | ||||
| STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); | ||||
| STBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); | ||||
|  | ||||
| STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); | ||||
| STBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| // | ||||
| // | ||||
| ////   end header file   ///////////////////////////////////////////////////// | ||||
| #endif // STBI_INCLUDE_STB_IMAGE_H | ||||
|  | ||||
| /* | ||||
|    revision history: | ||||
|       2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs | ||||
|       2.19  (2018-02-11) fix warning | ||||
|       2.18  (2018-01-30) fix warnings | ||||
|       2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug | ||||
|                          1-bit BMP | ||||
|                          *_is_16_bit api | ||||
|                          avoid warnings | ||||
|       2.16  (2017-07-23) all functions have 16-bit variants; | ||||
|                          STBI_NO_STDIO works again; | ||||
|                          compilation fixes; | ||||
|                          fix rounding in unpremultiply; | ||||
|                          optimize vertical flip; | ||||
|                          disable raw_len validation; | ||||
|                          documentation fixes | ||||
|       2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; | ||||
|                          warning fixes; disable run-time SSE detection on gcc; | ||||
|                          uniform handling of optional "return" values; | ||||
|                          thread-safe initialization of zlib tables | ||||
|       2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs | ||||
|       2.13  (2016-11-29) add 16-bit API, only supported for PNG right now | ||||
|       2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes | ||||
|       2.11  (2016-04-02) allocate large structures on the stack | ||||
|                          remove white matting for transparent PSD | ||||
|                          fix reported channel count for PNG & BMP | ||||
|                          re-enable SSE2 in non-gcc 64-bit | ||||
|                          support RGB-formatted JPEG | ||||
|                          read 16-bit PNGs (only as 8-bit) | ||||
|       2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED | ||||
|       2.09  (2016-01-16) allow comments in PNM files | ||||
|                          16-bit-per-pixel TGA (not bit-per-component) | ||||
|                          info() for TGA could break due to .hdr handling | ||||
|                          info() for BMP to shares code instead of sloppy parse | ||||
|                          can use STBI_REALLOC_SIZED if allocator doesn't support realloc | ||||
|                          code cleanup | ||||
|       2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA | ||||
|       2.07  (2015-09-13) fix compiler warnings | ||||
|                          partial animated GIF support | ||||
|                          limited 16-bpc PSD support | ||||
|                          #ifdef unused functions | ||||
|                          bug with < 92 byte PIC,PNM,HDR,TGA | ||||
|       2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value | ||||
|       2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning | ||||
|       2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit | ||||
|       2.03  (2015-04-12) extra corruption checking (mmozeiko) | ||||
|                          stbi_set_flip_vertically_on_load (nguillemot) | ||||
|                          fix NEON support; fix mingw support | ||||
|       2.02  (2015-01-19) fix incorrect assert, fix warning | ||||
|       2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 | ||||
|       2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG | ||||
|       2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) | ||||
|                          progressive JPEG (stb) | ||||
|                          PGM/PPM support (Ken Miller) | ||||
|                          STBI_MALLOC,STBI_REALLOC,STBI_FREE | ||||
|                          GIF bugfix -- seemingly never worked | ||||
|                          STBI_NO_*, STBI_ONLY_* | ||||
|       1.48  (2014-12-14) fix incorrectly-named assert() | ||||
|       1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) | ||||
|                          optimize PNG (ryg) | ||||
|                          fix bug in interlaced PNG with user-specified channel count (stb) | ||||
|       1.46  (2014-08-26) | ||||
|               fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG | ||||
|       1.45  (2014-08-16) | ||||
|               fix MSVC-ARM internal compiler error by wrapping malloc | ||||
|       1.44  (2014-08-07) | ||||
|               various warning fixes from Ronny Chevalier | ||||
|       1.43  (2014-07-15) | ||||
|               fix MSVC-only compiler problem in code changed in 1.42 | ||||
|       1.42  (2014-07-09) | ||||
|               don't define _CRT_SECURE_NO_WARNINGS (affects user code) | ||||
|               fixes to stbi__cleanup_jpeg path | ||||
|               added STBI_ASSERT to avoid requiring assert.h | ||||
|       1.41  (2014-06-25) | ||||
|               fix search&replace from 1.36 that messed up comments/error messages | ||||
|       1.40  (2014-06-22) | ||||
|               fix gcc struct-initialization warning | ||||
|       1.39  (2014-06-15) | ||||
|               fix to TGA optimization when req_comp != number of components in TGA; | ||||
|               fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) | ||||
|               add support for BMP version 5 (more ignored fields) | ||||
|       1.38  (2014-06-06) | ||||
|               suppress MSVC warnings on integer casts truncating values | ||||
|               fix accidental rename of 'skip' field of I/O | ||||
|       1.37  (2014-06-04) | ||||
|               remove duplicate typedef | ||||
|       1.36  (2014-06-03) | ||||
|               convert to header file single-file library | ||||
|               if de-iphone isn't set, load iphone images color-swapped instead of returning NULL | ||||
|       1.35  (2014-05-27) | ||||
|               various warnings | ||||
|               fix broken STBI_SIMD path | ||||
|               fix bug where stbi_load_from_file no longer left file pointer in correct place | ||||
|               fix broken non-easy path for 32-bit BMP (possibly never used) | ||||
|               TGA optimization by Arseny Kapoulkine | ||||
|       1.34  (unknown) | ||||
|               use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case | ||||
|       1.33  (2011-07-14) | ||||
|               make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements | ||||
|       1.32  (2011-07-13) | ||||
|               support for "info" function for all supported filetypes (SpartanJ) | ||||
|       1.31  (2011-06-20) | ||||
|               a few more leak fixes, bug in PNG handling (SpartanJ) | ||||
|       1.30  (2011-06-11) | ||||
|               added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) | ||||
|               removed deprecated format-specific test/load functions | ||||
|               removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway | ||||
|               error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) | ||||
|               fix inefficiency in decoding 32-bit BMP (David Woo) | ||||
|       1.29  (2010-08-16) | ||||
|               various warning fixes from Aurelien Pocheville | ||||
|       1.28  (2010-08-01) | ||||
|               fix bug in GIF palette transparency (SpartanJ) | ||||
|       1.27  (2010-08-01) | ||||
|               cast-to-stbi_uc to fix warnings | ||||
|       1.26  (2010-07-24) | ||||
|               fix bug in file buffering for PNG reported by SpartanJ | ||||
|       1.25  (2010-07-17) | ||||
|               refix trans_data warning (Won Chun) | ||||
|       1.24  (2010-07-12) | ||||
|               perf improvements reading from files on platforms with lock-heavy fgetc() | ||||
|               minor perf improvements for jpeg | ||||
|               deprecated type-specific functions so we'll get feedback if they're needed | ||||
|               attempt to fix trans_data warning (Won Chun) | ||||
|       1.23    fixed bug in iPhone support | ||||
|       1.22  (2010-07-10) | ||||
|               removed image *writing* support | ||||
|               stbi_info support from Jetro Lauha | ||||
|               GIF support from Jean-Marc Lienher | ||||
|               iPhone PNG-extensions from James Brown | ||||
|               warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) | ||||
|       1.21    fix use of 'stbi_uc' in header (reported by jon blow) | ||||
|       1.20    added support for Softimage PIC, by Tom Seddon | ||||
|       1.19    bug in interlaced PNG corruption check (found by ryg) | ||||
|       1.18  (2008-08-02) | ||||
|               fix a threading bug (local mutable static) | ||||
|       1.17    support interlaced PNG | ||||
|       1.16    major bugfix - stbi__convert_format converted one too many pixels | ||||
|       1.15    initialize some fields for thread safety | ||||
|       1.14    fix threadsafe conversion bug | ||||
|               header-file-only version (#define STBI_HEADER_FILE_ONLY before including) | ||||
|       1.13    threadsafe | ||||
|       1.12    const qualifiers in the API | ||||
|       1.11    Support installable IDCT, colorspace conversion routines | ||||
|       1.10    Fixes for 64-bit (don't use "unsigned long") | ||||
|               optimized upsampling by Fabian "ryg" Giesen | ||||
|       1.09    Fix format-conversion for PSD code (bad global variables!) | ||||
|       1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz | ||||
|       1.07    attempt to fix C++ warning/errors again | ||||
|       1.06    attempt to fix C++ warning/errors again | ||||
|       1.05    fix TGA loading to return correct *comp and use good luminance calc | ||||
|       1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free | ||||
|       1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR | ||||
|       1.02    support for (subset of) HDR files, float interface for preferred access to them | ||||
|       1.01    fix bug: possible bug in handling right-side up bmps... not sure | ||||
|               fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all | ||||
|       1.00    interface to zlib that skips zlib header | ||||
|       0.99    correct handling of alpha in palette | ||||
|       0.98    TGA loader by lonesock; dynamically add loaders (untested) | ||||
|       0.97    jpeg errors on too large a file; also catch another malloc failure | ||||
|       0.96    fix detection of invalid v value - particleman@mollyrocket forum | ||||
|       0.95    during header scan, seek to markers in case of padding | ||||
|       0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same | ||||
|       0.93    handle jpegtran output; verbose errors | ||||
|       0.92    read 4,8,16,24,32-bit BMP files of several formats | ||||
|       0.91    output 24-bit Windows 3.0 BMP files | ||||
|       0.90    fix a few more warnings; bump version number to approach 1.0 | ||||
|       0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd | ||||
|       0.60    fix compiling as c++ | ||||
|       0.59    fix warnings: merge Dave Moore's -Wall fixes | ||||
|       0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian | ||||
|       0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available | ||||
|       0.56    fix bug: zlib uncompressed mode len vs. nlen | ||||
|       0.55    fix bug: restart_interval not initialized to 0 | ||||
|       0.54    allow NULL for 'int *comp' | ||||
|       0.53    fix bug in png 3->4; speedup png decoding | ||||
|       0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments | ||||
|       0.51    obey req_comp requests, 1-component jpegs return as 1-component, | ||||
|               on 'test' only check type, not whether we support this variant | ||||
|       0.50  (2006-11-19) | ||||
|               first released version | ||||
| */ | ||||
|  | ||||
|  | ||||
| /* | ||||
| ------------------------------------------------------------------------------ | ||||
| This software is available under 2 licenses -- choose whichever you prefer. | ||||
| ------------------------------------------------------------------------------ | ||||
| ALTERNATIVE A - MIT License | ||||
| Copyright (c) 2017 Sean Barrett | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||||
| of the Software, and to permit persons to whom the Software is furnished to do | ||||
| so, subject to the following conditions: | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
| ------------------------------------------------------------------------------ | ||||
| ALTERNATIVE B - Public Domain (www.unlicense.org) | ||||
| This is free and unencumbered software released into the public domain. | ||||
| Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | ||||
| software, either in source code form or as a compiled binary, for any purpose, | ||||
| commercial or non-commercial, and by any means. | ||||
| In jurisdictions that recognize copyright laws, the author or authors of this | ||||
| software dedicate any and all copyright interest in the software to the public | ||||
| domain. We make this dedication for the benefit of the public at large and to | ||||
| the detriment of our heirs and successors. We intend this dedication to be an | ||||
| overt act of relinquishment in perpetuity of all present and future rights to | ||||
| this software under copyright law. | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| ------------------------------------------------------------------------------ | ||||
| */ | ||||
							
								
								
									
										2282
									
								
								externals/stb/stb_image_resize.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2282
									
								
								externals/stb/stb_image_resize.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										426
									
								
								externals/stb/stb_image_resize.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										426
									
								
								externals/stb/stb_image_resize.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,426 @@ | ||||
| // SPDX-FileCopyrightText: Jorge L Rodriguez | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| /* stb_image_resize - v0.97 - public domain image resizing | ||||
|    by Jorge L Rodriguez (@VinoBS) - 2014 | ||||
|    http://github.com/nothings/stb | ||||
|  | ||||
|    Written with emphasis on usability, portability, and efficiency. (No | ||||
|    SIMD or threads, so it be easily outperformed by libs that use those.) | ||||
|    Only scaling and translation is supported, no rotations or shears. | ||||
|    Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. | ||||
|  | ||||
|    COMPILING & LINKING | ||||
|       In one C/C++ file that #includes this file, do this: | ||||
|          #define STB_IMAGE_RESIZE_IMPLEMENTATION | ||||
|       before the #include. That will create the implementation in that file. | ||||
|  | ||||
|    QUICKSTART | ||||
|       stbir_resize_uint8(      input_pixels , in_w , in_h , 0, | ||||
|                                output_pixels, out_w, out_h, 0, num_channels) | ||||
|       stbir_resize_float(...) | ||||
|       stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, | ||||
|                                output_pixels, out_w, out_h, 0, | ||||
|                                num_channels , alpha_chan  , 0) | ||||
|       stbir_resize_uint8_srgb_edgemode( | ||||
|                                input_pixels , in_w , in_h , 0, | ||||
|                                output_pixels, out_w, out_h, 0, | ||||
|                                num_channels , alpha_chan  , 0, STBIR_EDGE_CLAMP) | ||||
|                                                             // WRAP/REFLECT/ZERO | ||||
|  | ||||
|    FULL API | ||||
|       See the "header file" section of the source for API documentation. | ||||
|  | ||||
|    ADDITIONAL DOCUMENTATION | ||||
|  | ||||
|       SRGB & FLOATING POINT REPRESENTATION | ||||
|          The sRGB functions presume IEEE floating point. If you do not have | ||||
|          IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use | ||||
|          a slower implementation. | ||||
|  | ||||
|       MEMORY ALLOCATION | ||||
|          The resize functions here perform a single memory allocation using | ||||
|          malloc. To control the memory allocation, before the #include that | ||||
|          triggers the implementation, do: | ||||
|  | ||||
|             #define STBIR_MALLOC(size,context) ... | ||||
|             #define STBIR_FREE(ptr,context)   ... | ||||
|  | ||||
|          Each resize function makes exactly one call to malloc/free, so to use | ||||
|          temp memory, store the temp memory in the context and return that. | ||||
|  | ||||
|       ASSERT | ||||
|          Define STBIR_ASSERT(boolval) to override assert() and not use assert.h | ||||
|  | ||||
|       OPTIMIZATION | ||||
|          Define STBIR_SATURATE_INT to compute clamp values in-range using | ||||
|          integer operations instead of float operations. This may be faster | ||||
|          on some platforms. | ||||
|  | ||||
|       DEFAULT FILTERS | ||||
|          For functions which don't provide explicit control over what filters | ||||
|          to use, you can change the compile-time defaults with | ||||
|  | ||||
|             #define STBIR_DEFAULT_FILTER_UPSAMPLE     STBIR_FILTER_something | ||||
|             #define STBIR_DEFAULT_FILTER_DOWNSAMPLE   STBIR_FILTER_something | ||||
|  | ||||
|          See stbir_filter in the header-file section for the list of filters. | ||||
|  | ||||
|       NEW FILTERS | ||||
|          A number of 1D filter kernels are used. For a list of | ||||
|          supported filters see the stbir_filter enum. To add a new filter, | ||||
|          write a filter function and add it to stbir__filter_info_table. | ||||
|  | ||||
|       PROGRESS | ||||
|          For interactive use with slow resize operations, you can install | ||||
|          a progress-report callback: | ||||
|  | ||||
|             #define STBIR_PROGRESS_REPORT(val)   some_func(val) | ||||
|  | ||||
|          The parameter val is a float which goes from 0 to 1 as progress is made. | ||||
|  | ||||
|          For example: | ||||
|  | ||||
|             static void my_progress_report(float progress); | ||||
|             #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) | ||||
|  | ||||
|             #define STB_IMAGE_RESIZE_IMPLEMENTATION | ||||
|             #include "stb_image_resize.h" | ||||
|  | ||||
|             static void my_progress_report(float progress) | ||||
|             { | ||||
|                printf("Progress: %f%%\n", progress*100); | ||||
|             } | ||||
|  | ||||
|       MAX CHANNELS | ||||
|          If your image has more than 64 channels, define STBIR_MAX_CHANNELS | ||||
|          to the max you'll have. | ||||
|  | ||||
|       ALPHA CHANNEL | ||||
|          Most of the resizing functions provide the ability to control how | ||||
|          the alpha channel of an image is processed. The important things | ||||
|          to know about this: | ||||
|  | ||||
|          1. The best mathematically-behaved version of alpha to use is | ||||
|          called "premultiplied alpha", in which the other color channels | ||||
|          have had the alpha value multiplied in. If you use premultiplied | ||||
|          alpha, linear filtering (such as image resampling done by this | ||||
|          library, or performed in texture units on GPUs) does the "right | ||||
|          thing". While premultiplied alpha is standard in the movie CGI | ||||
|          industry, it is still uncommon in the videogame/real-time world. | ||||
|  | ||||
|          If you linearly filter non-premultiplied alpha, strange effects | ||||
|          occur. (For example, the 50/50 average of 99% transparent bright green | ||||
|          and 1% transparent black produces 50% transparent dark green when | ||||
|          non-premultiplied, whereas premultiplied it produces 50% | ||||
|          transparent near-black. The former introduces green energy | ||||
|          that doesn't exist in the source image.) | ||||
|  | ||||
|          2. Artists should not edit premultiplied-alpha images; artists | ||||
|          want non-premultiplied alpha images. Thus, art tools generally output | ||||
|          non-premultiplied alpha images. | ||||
|  | ||||
|          3. You will get best results in most cases by converting images | ||||
|          to premultiplied alpha before processing them mathematically. | ||||
|  | ||||
|          4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the | ||||
|          resizer does not do anything special for the alpha channel; | ||||
|          it is resampled identically to other channels. This produces | ||||
|          the correct results for premultiplied-alpha images, but produces | ||||
|          less-than-ideal results for non-premultiplied-alpha images. | ||||
|  | ||||
|          5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, | ||||
|          then the resizer weights the contribution of input pixels | ||||
|          based on their alpha values, or, equivalently, it multiplies | ||||
|          the alpha value into the color channels, resamples, then divides | ||||
|          by the resultant alpha value. Input pixels which have alpha=0 do | ||||
|          not contribute at all to output pixels unless _all_ of the input | ||||
|          pixels affecting that output pixel have alpha=0, in which case | ||||
|          the result for that pixel is the same as it would be without | ||||
|          STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for | ||||
|          input images in integer formats. For input images in float format, | ||||
|          input pixels with alpha=0 have no effect, and output pixels | ||||
|          which have alpha=0 will be 0 in all channels. (For float images, | ||||
|          you can manually achieve the same result by adding a tiny epsilon | ||||
|          value to the alpha channel of every image, and then subtracting | ||||
|          or clamping it at the end.) | ||||
|  | ||||
|          6. You can suppress the behavior described in #5 and make | ||||
|          all-0-alpha pixels have 0 in all channels by #defining | ||||
|          STBIR_NO_ALPHA_EPSILON. | ||||
|  | ||||
|          7. You can separately control whether the alpha channel is | ||||
|          interpreted as linear or affected by the colorspace. By default | ||||
|          it is linear; you almost never want to apply the colorspace. | ||||
|          (For example, graphics hardware does not apply sRGB conversion | ||||
|          to the alpha channel.) | ||||
|  | ||||
|    CONTRIBUTORS | ||||
|       Jorge L Rodriguez: Implementation | ||||
|       Sean Barrett: API design, optimizations | ||||
|       Aras Pranckevicius: bugfix | ||||
|       Nathan Reed: warning fixes | ||||
|  | ||||
|    REVISIONS | ||||
|       0.97 (2020-02-02) fixed warning | ||||
|       0.96 (2019-03-04) fixed warnings | ||||
|       0.95 (2017-07-23) fixed warnings | ||||
|       0.94 (2017-03-18) fixed warnings | ||||
|       0.93 (2017-03-03) fixed bug with certain combinations of heights | ||||
|       0.92 (2017-01-02) fix integer overflow on large (>2GB) images | ||||
|       0.91 (2016-04-02) fix warnings; fix handling of subpixel regions | ||||
|       0.90 (2014-09-17) first released version | ||||
|  | ||||
|    LICENSE | ||||
|      See end of file for license information. | ||||
|  | ||||
|    TODO | ||||
|       Don't decode all of the image data when only processing a partial tile | ||||
|       Don't use full-width decode buffers when only processing a partial tile | ||||
|       When processing wide images, break processing into tiles so data fits in L1 cache | ||||
|       Installable filters? | ||||
|       Resize that respects alpha test coverage | ||||
|          (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: | ||||
|          https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) | ||||
| */ | ||||
|  | ||||
| #ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H | ||||
| #define STBIR_INCLUDE_STB_IMAGE_RESIZE_H | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| typedef unsigned char  stbir_uint8; | ||||
| typedef unsigned short stbir_uint16; | ||||
| typedef unsigned int   stbir_uint32; | ||||
| #else | ||||
| #include <stdint.h> | ||||
| typedef uint8_t  stbir_uint8; | ||||
| typedef uint16_t stbir_uint16; | ||||
| typedef uint32_t stbir_uint32; | ||||
| #endif | ||||
|  | ||||
| #ifndef STBIRDEF | ||||
| #ifdef STB_IMAGE_RESIZE_STATIC | ||||
| #define STBIRDEF static | ||||
| #else | ||||
| #ifdef __cplusplus | ||||
| #define STBIRDEF extern "C" | ||||
| #else | ||||
| #define STBIRDEF extern | ||||
| #endif | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // Easy-to-use API: | ||||
| // | ||||
| //     * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) | ||||
| //     * input_w is input image width (x-axis), input_h is input image height (y-axis) | ||||
| //     * stride is the offset between successive rows of image data in memory, in bytes. you can | ||||
| //       specify 0 to mean packed continuously in memory | ||||
| //     * alpha channel is treated identically to other channels. | ||||
| //     * colorspace is linear or sRGB as specified by function name | ||||
| //     * returned result is 1 for success or 0 in case of an error. | ||||
| //       #define STBIR_ASSERT() to trigger an assert on parameter validation errors. | ||||
| //     * Memory required grows approximately linearly with input and output size, but with | ||||
| //       discontinuities at input_w == output_w and input_h == output_h. | ||||
| //     * These functions use a "default" resampling filter defined at compile time. To change the filter, | ||||
| //       you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE | ||||
| //       and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. | ||||
|  | ||||
| STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                            unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                      int num_channels); | ||||
|  | ||||
| STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                            float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                      int num_channels); | ||||
|  | ||||
|  | ||||
| // The following functions interpret image data as gamma-corrected sRGB. | ||||
| // Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, | ||||
| // or otherwise provide the index of the alpha channel. Flags value | ||||
| // of 0 will probably do the right thing if you're not sure what | ||||
| // the flags mean. | ||||
|  | ||||
| #define STBIR_ALPHA_CHANNEL_NONE       -1 | ||||
|  | ||||
| // Set this flag if your texture has premultiplied alpha. Otherwise, stbir will | ||||
| // use alpha-weighted resampling (effectively premultiplying, resampling, | ||||
| // then unpremultiplying). | ||||
| #define STBIR_FLAG_ALPHA_PREMULTIPLIED    (1 << 0) | ||||
| // The specified alpha channel should be handled as gamma-corrected value even | ||||
| // when doing sRGB operations. | ||||
| #define STBIR_FLAG_ALPHA_USES_COLORSPACE  (1 << 1) | ||||
|  | ||||
| STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                            unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                      int num_channels, int alpha_channel, int flags); | ||||
|  | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     STBIR_EDGE_CLAMP   = 1, | ||||
|     STBIR_EDGE_REFLECT = 2, | ||||
|     STBIR_EDGE_WRAP    = 3, | ||||
|     STBIR_EDGE_ZERO    = 4, | ||||
| } stbir_edge; | ||||
|  | ||||
| // This function adds the ability to specify how requests to sample off the edge of the image are handled. | ||||
| STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                                     unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                               int num_channels, int alpha_channel, int flags, | ||||
|                                               stbir_edge edge_wrap_mode); | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // Medium-complexity API | ||||
| // | ||||
| // This extends the easy-to-use API as follows: | ||||
| // | ||||
| //     * Alpha-channel can be processed separately | ||||
| //       * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE | ||||
| //         * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) | ||||
| //         * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) | ||||
| //     * Filter can be selected explicitly | ||||
| //     * uint16 image type | ||||
| //     * sRGB colorspace available for all types | ||||
| //     * context parameter for passing to STBIR_MALLOC | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses | ||||
|     STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios | ||||
|     STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering | ||||
|     STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque | ||||
|     STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline | ||||
|     STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3 | ||||
| } stbir_filter; | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     STBIR_COLORSPACE_LINEAR, | ||||
|     STBIR_COLORSPACE_SRGB, | ||||
|  | ||||
|     STBIR_MAX_COLORSPACES, | ||||
| } stbir_colorspace; | ||||
|  | ||||
| // The following functions are all identical except for the type of the image data | ||||
|  | ||||
| STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                                unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                          int num_channels, int alpha_channel, int flags, | ||||
|                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, | ||||
|                                          void *alloc_context); | ||||
|  | ||||
| STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                                stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                          int num_channels, int alpha_channel, int flags, | ||||
|                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, | ||||
|                                          void *alloc_context); | ||||
|  | ||||
| STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                                float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                          int num_channels, int alpha_channel, int flags, | ||||
|                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, | ||||
|                                          void *alloc_context); | ||||
|  | ||||
|  | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // Full-complexity API | ||||
| // | ||||
| // This extends the medium API as follows: | ||||
| // | ||||
| //       * uint32 image type | ||||
| //     * not typesafe | ||||
| //     * separate filter types for each axis | ||||
| //     * separate edge modes for each axis | ||||
| //     * can specify scale explicitly for subpixel correctness | ||||
| //     * can specify image source tile using texture coordinates | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     STBIR_TYPE_UINT8 , | ||||
|     STBIR_TYPE_UINT16, | ||||
|     STBIR_TYPE_UINT32, | ||||
|     STBIR_TYPE_FLOAT , | ||||
|  | ||||
|     STBIR_MAX_TYPES | ||||
| } stbir_datatype; | ||||
|  | ||||
| STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                    stbir_datatype datatype, | ||||
|                                    int num_channels, int alpha_channel, int flags, | ||||
|                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, | ||||
|                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical, | ||||
|                                    stbir_colorspace space, void *alloc_context); | ||||
|  | ||||
| STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                    stbir_datatype datatype, | ||||
|                                    int num_channels, int alpha_channel, int flags, | ||||
|                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, | ||||
|                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical, | ||||
|                                    stbir_colorspace space, void *alloc_context, | ||||
|                                    float x_scale, float y_scale, | ||||
|                                    float x_offset, float y_offset); | ||||
|  | ||||
| STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, | ||||
|                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, | ||||
|                                    stbir_datatype datatype, | ||||
|                                    int num_channels, int alpha_channel, int flags, | ||||
|                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, | ||||
|                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical, | ||||
|                                    stbir_colorspace space, void *alloc_context, | ||||
|                                    float s0, float t0, float s1, float t1); | ||||
| // (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. | ||||
|  | ||||
| // | ||||
| // | ||||
| ////   end header file   ///////////////////////////////////////////////////// | ||||
| #endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H | ||||
|  | ||||
| /* | ||||
| ------------------------------------------------------------------------------ | ||||
| This software is available under 2 licenses -- choose whichever you prefer. | ||||
| ------------------------------------------------------------------------------ | ||||
| ALTERNATIVE A - MIT License | ||||
| Copyright (c) 2017 Sean Barrett | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||||
| of the Software, and to permit persons to whom the Software is furnished to do | ||||
| so, subject to the following conditions: | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
| ------------------------------------------------------------------------------ | ||||
| ALTERNATIVE B - Public Domain (www.unlicense.org) | ||||
| This is free and unencumbered software released into the public domain. | ||||
| Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | ||||
| software, either in source code form or as a compiled binary, for any purpose, | ||||
| commercial or non-commercial, and by any means. | ||||
| In jurisdictions that recognize copyright laws, the author or authors of this | ||||
| software dedicate any and all copyright interest in the software to the public | ||||
| domain. We make this dedication for the benefit of the public at large and to | ||||
| the detriment of our heirs and successors. We intend this dedication to be an | ||||
| overt act of relinquishment in perpetuity of all present and future rights to | ||||
| this software under copyright law. | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||
| ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| ------------------------------------------------------------------------------ | ||||
| */ | ||||
| @@ -466,14 +466,18 @@ add_library(core STATIC | ||||
|     hle/service/caps/caps_a.h | ||||
|     hle/service/caps/caps_c.cpp | ||||
|     hle/service/caps/caps_c.h | ||||
|     hle/service/caps/caps_u.cpp | ||||
|     hle/service/caps/caps_u.h | ||||
|     hle/service/caps/caps_manager.cpp | ||||
|     hle/service/caps/caps_manager.h | ||||
|     hle/service/caps/caps_result.h | ||||
|     hle/service/caps/caps_sc.cpp | ||||
|     hle/service/caps/caps_sc.h | ||||
|     hle/service/caps/caps_ss.cpp | ||||
|     hle/service/caps/caps_ss.h | ||||
|     hle/service/caps/caps_su.cpp | ||||
|     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.h | ||||
|     hle/service/es/es.cpp | ||||
|   | ||||
| @@ -31,7 +31,7 @@ | ||||
| #include "core/hle/service/apm/apm_controller.h" | ||||
| #include "core/hle/service/apm/apm_interface.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/ipc_helpers.h" | ||||
| #include "core/hle/service/ns/ns.h" | ||||
| @@ -764,6 +764,66 @@ void AppletMessageQueue::OperationModeChanged() { | ||||
|     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_, | ||||
|                                        std::shared_ptr<AppletMessageQueue> msg_queue_) | ||||
|     : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, | ||||
| @@ -787,7 +847,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, | ||||
|         {14, nullptr, "GetWakeupCount"}, | ||||
|         {20, nullptr, "PushToGeneralChannel"}, | ||||
|         {30, nullptr, "GetHomeButtonReaderLockAccessor"}, | ||||
|         {31, nullptr, "GetReaderLockAccessorEx"}, | ||||
|         {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, | ||||
|         {32, nullptr, "GetWriterLockAccessorEx"}, | ||||
|         {40, nullptr, "GetCradleFwVersion"}, | ||||
|         {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, | ||||
| @@ -805,7 +865,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, | ||||
|         {65, nullptr, "GetApplicationIdByContentActionName"}, | ||||
|         {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, | ||||
|         {67, nullptr, "CancelCpuBoostMode"}, | ||||
|         {68, nullptr, "GetBuiltInDisplayType"}, | ||||
|         {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"}, | ||||
|         {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, | ||||
|         {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, | ||||
|         {91, nullptr, "GetCurrentPerformanceConfiguration"}, | ||||
| @@ -886,6 +946,18 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { | ||||
|     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) { | ||||
|     LOG_WARNING(Service_AM, "called"); | ||||
|  | ||||
| @@ -970,6 +1042,14 @@ void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& 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) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto system_button{rp.PopEnum<SystemButtonType>()}; | ||||
| @@ -1493,6 +1573,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) | ||||
|     case Applets::AppletId::MiiEdit: | ||||
|         PushInShowMiiEditData(); | ||||
|         break; | ||||
|     case Applets::AppletId::PhotoViewer: | ||||
|         PushInShowAlbum(); | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| @@ -1569,6 +1652,23 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& | ||||
|     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() { | ||||
|     const Applets::CommonArguments arguments{ | ||||
|         .arguments_version = Applets::CommonArgumentVersion::Version3, | ||||
|   | ||||
| @@ -195,6 +195,23 @@ private: | ||||
|     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> { | ||||
| public: | ||||
|     explicit ICommonStateGetter(Core::System& system_, | ||||
| @@ -237,6 +254,7 @@ private: | ||||
|     void GetCurrentFocusState(HLERequestContext& ctx); | ||||
|     void RequestToAcquireSleepLock(HLERequestContext& ctx); | ||||
|     void GetAcquiredSleepLockEvent(HLERequestContext& ctx); | ||||
|     void GetReaderLockAccessorEx(HLERequestContext& ctx); | ||||
|     void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); | ||||
|     void GetOperationMode(HLERequestContext& ctx); | ||||
|     void GetPerformanceMode(HLERequestContext& ctx); | ||||
| @@ -248,6 +266,7 @@ private: | ||||
|     void EndVrModeEx(HLERequestContext& ctx); | ||||
|     void GetDefaultDisplayResolution(HLERequestContext& ctx); | ||||
|     void SetCpuBoostMode(HLERequestContext& ctx); | ||||
|     void GetBuiltInDisplayType(HLERequestContext& ctx); | ||||
|     void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); | ||||
|     void GetSettingsPlatformRegion(HLERequestContext& ctx); | ||||
|     void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); | ||||
| @@ -327,6 +346,7 @@ private: | ||||
|     void ExitProcessAndReturn(HLERequestContext& ctx); | ||||
|     void GetCallerAppletIdentityInfo(HLERequestContext& ctx); | ||||
|  | ||||
|     void PushInShowAlbum(); | ||||
|     void PushInShowCabinetData(); | ||||
|     void PushInShowMiiEditData(); | ||||
|  | ||||
|   | ||||
| @@ -28,8 +28,8 @@ public: | ||||
|             {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, | ||||
|             {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, | ||||
|             {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, | ||||
|             {22, nullptr, "GetHomeMenuFunctions"}, | ||||
|             {23, nullptr, "GetGlobalStateController"}, | ||||
|             {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, | ||||
|             {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, | ||||
|             {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, | ||||
|         }; | ||||
|         // clang-format on | ||||
| @@ -110,6 +110,22 @@ private: | ||||
|         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) { | ||||
|         LOG_DEBUG(Service_AM, "called"); | ||||
|  | ||||
|   | ||||
| @@ -138,6 +138,10 @@ void Error::Initialize() { | ||||
|         CopyArgumentData(data, args->application_error); | ||||
|         error_code = Result(args->application_error.error_code); | ||||
|         break; | ||||
|     case ErrorAppletMode::ShowErrorPctl: | ||||
|         CopyArgumentData(data, args->error_record); | ||||
|         error_code = Decode64BitError(args->error_record.error_code_64); | ||||
|         break; | ||||
|     case ErrorAppletMode::ShowErrorRecord: | ||||
|         CopyArgumentData(data, args->error_record); | ||||
|         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); | ||||
|         break; | ||||
|     } | ||||
|     case ErrorAppletMode::ShowErrorPctl: | ||||
|     case ErrorAppletMode::ShowErrorRecord: | ||||
|         reporter.SaveErrorReport(title_id, error_code, | ||||
|                                  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_a.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_ss.h" | ||||
| #include "core/hle/service/caps/caps_su.h" | ||||
| @@ -15,13 +16,21 @@ namespace Service::Capture { | ||||
|  | ||||
| void LoopProcess(Core::System& 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)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,93 +3,12 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
|  | ||||
| namespace Service::SM { | ||||
| class ServiceManager; | ||||
| } | ||||
|  | ||||
| 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); | ||||
|  | ||||
| } // namespace Service::Capture | ||||
|   | ||||
| @@ -1,40 +1,26 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||||
| // 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_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 { | ||||
|  | ||||
| class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { | ||||
| public: | ||||
|     explicit IAlbumAccessorSession(Core::System& system_) | ||||
|         : 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"} { | ||||
| IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, | ||||
|                                              std::shared_ptr<AlbumManager> album_manager) | ||||
|     : ServiceFramework{system_, "caps:a"}, manager{album_manager} { | ||||
|     // clang-format off | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, nullptr, "GetAlbumFileCount"}, | ||||
|         {1, nullptr, "GetAlbumFileList"}, | ||||
|         {2, nullptr, "LoadAlbumFile"}, | ||||
|         {3, nullptr, "DeleteAlbumFile"}, | ||||
|         {3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"}, | ||||
|         {4, nullptr, "StorageCopyAlbumFile"}, | ||||
|         {5, nullptr, "IsAlbumMounted"}, | ||||
|         {5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"}, | ||||
|         {6, nullptr, "GetAlbumUsage"}, | ||||
|         {7, nullptr, "GetAlbumFileSize"}, | ||||
|         {8, nullptr, "LoadAlbumFileThumbnail"}, | ||||
| @@ -47,18 +33,18 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} { | ||||
|         {15, nullptr, "GetAlbumUsage3"}, | ||||
|         {16, nullptr, "GetAlbumMountResult"}, | ||||
|         {17, nullptr, "GetAlbumUsage16"}, | ||||
|         {18, nullptr, "Unknown18"}, | ||||
|         {18, &IAlbumAccessorService::Unknown18, "Unknown18"}, | ||||
|         {19, nullptr, "Unknown19"}, | ||||
|         {100, nullptr, "GetAlbumFileCountEx0"}, | ||||
|         {101, nullptr, "GetAlbumFileListEx0"}, | ||||
|         {101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"}, | ||||
|         {202, nullptr, "SaveEditedScreenShot"}, | ||||
|         {301, nullptr, "GetLastThumbnail"}, | ||||
|         {302, nullptr, "GetLastOverlayMovieThumbnail"}, | ||||
|         {401, nullptr, "GetAutoSavingStorage"}, | ||||
|         {401,  &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"}, | ||||
|         {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, | ||||
|         {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"}, | ||||
|         {1002, nullptr, "LoadAlbumScreenShotImageEx1"}, | ||||
|         {1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"}, | ||||
|         {1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"}, | ||||
|         {1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"}, | ||||
|         {8001, nullptr, "ForceAlbumUnmounted"}, | ||||
|         {8002, nullptr, "ResetAlbumMountStatus"}, | ||||
|         {8011, nullptr, "RefreshAlbumCache"}, | ||||
| @@ -74,6 +60,199 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} { | ||||
|     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 | ||||
|   | ||||
| @@ -10,11 +10,26 @@ class System; | ||||
| } | ||||
|  | ||||
| namespace Service::Capture { | ||||
| class AlbumManager; | ||||
|  | ||||
| class CAPS_A final : public ServiceFramework<CAPS_A> { | ||||
| class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> { | ||||
| public: | ||||
|     explicit CAPS_A(Core::System& system_); | ||||
|     ~CAPS_A() override; | ||||
|     explicit IAlbumAccessorService(Core::System& system_, | ||||
|                                    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 | ||||
|   | ||||
| @@ -3,53 +3,21 @@ | ||||
|  | ||||
| #include "common/logging/log.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" | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { | ||||
| public: | ||||
|     explicit IAlbumControlSession(Core::System& system_) | ||||
|         : 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"} { | ||||
| IAlbumControlService::IAlbumControlService(Core::System& system_, | ||||
|                                            std::shared_ptr<AlbumManager> album_manager) | ||||
|     : ServiceFramework{system_, "caps:c"}, manager{album_manager} { | ||||
|     // clang-format off | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {1, nullptr, "CaptureRawImage"}, | ||||
|         {2, nullptr, "CaptureRawImageWithTimeout"}, | ||||
|         {33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {1001, nullptr, "RequestTakingScreenShot"}, | ||||
|         {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, | ||||
|         {1011, nullptr, "NotifyTakingScreenShotRefused"}, | ||||
| @@ -72,9 +40,9 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} { | ||||
|     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}; | ||||
|     const auto library_version{rp.Pop<u64>()}; | ||||
|     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||
|   | ||||
| @@ -10,14 +10,18 @@ class System; | ||||
| } | ||||
|  | ||||
| namespace Service::Capture { | ||||
| class AlbumManager; | ||||
|  | ||||
| class CAPS_C final : public ServiceFramework<CAPS_C> { | ||||
| class IAlbumControlService final : public ServiceFramework<IAlbumControlService> { | ||||
| public: | ||||
|     explicit CAPS_C(Core::System& system_); | ||||
|     ~CAPS_C() override; | ||||
|     explicit IAlbumControlService(Core::System& system_, | ||||
|                                   std::shared_ptr<AlbumManager> album_manager); | ||||
|     ~IAlbumControlService() override; | ||||
|  | ||||
| private: | ||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||
|  | ||||
|     std::shared_ptr<AlbumManager> manager = nullptr; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Capture | ||||
|   | ||||
							
								
								
									
										342
									
								
								src/core/hle/service/caps/caps_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								src/core/hle/service/caps/caps_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,342 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include <sstream> | ||||
| #include <stb_image.h> | ||||
| #include <stb_image_resize.h> | ||||
|  | ||||
| #include "common/fs/file.h" | ||||
| #include "common/fs/path_util.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/service/caps/caps_manager.h" | ||||
| #include "core/hle/service/caps/caps_result.h" | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| AlbumManager::AlbumManager() {} | ||||
|  | ||||
| AlbumManager::~AlbumManager() = default; | ||||
|  | ||||
| Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) { | ||||
|     if (file_id.storage > AlbumStorage::Sd) { | ||||
|         return ResultInvalidStorage; | ||||
|     } | ||||
|  | ||||
|     if (!is_mounted) { | ||||
|         return ResultIsNotMounted; | ||||
|     } | ||||
|  | ||||
|     std::filesystem::path path; | ||||
|     const auto result = GetFile(path, file_id); | ||||
|  | ||||
|     if (result.IsError()) { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     if (!Common::FS::RemoveFile(path)) { | ||||
|         return ResultFileNotFound; | ||||
|     } | ||||
|  | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::IsAlbumMounted(AlbumStorage storage) { | ||||
|     if (storage > AlbumStorage::Sd) { | ||||
|         return ResultInvalidStorage; | ||||
|     } | ||||
|  | ||||
|     is_mounted = true; | ||||
|  | ||||
|     if (storage == AlbumStorage::Sd) { | ||||
|         FindScreenshots(); | ||||
|     } | ||||
|  | ||||
|     return is_mounted ? ResultSuccess : ResultIsNotMounted; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, | ||||
|                                       u8 flags) const { | ||||
|     if (storage > AlbumStorage::Sd) { | ||||
|         return ResultInvalidStorage; | ||||
|     } | ||||
|  | ||||
|     if (!is_mounted) { | ||||
|         return ResultIsNotMounted; | ||||
|     } | ||||
|  | ||||
|     for (auto& [file_id, path] : album_files) { | ||||
|         if (file_id.storage != storage) { | ||||
|             continue; | ||||
|         } | ||||
|         if (out_entries.size() >= SdAlbumFileLimit) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         const auto entry_size = Common::FS::GetSize(path); | ||||
|         out_entries.push_back({ | ||||
|             .entry_size = entry_size, | ||||
|             .file_id = file_id, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, | ||||
|                                       ContentType contex_type, AlbumFileDateTime start_date, | ||||
|                                       AlbumFileDateTime end_date, u64 aruid) const { | ||||
|     if (!is_mounted) { | ||||
|         return ResultIsNotMounted; | ||||
|     } | ||||
|  | ||||
|     for (auto& [file_id, path] : album_files) { | ||||
|         if (file_id.type != contex_type) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (file_id.date > start_date) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (file_id.date < end_date) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (out_entries.size() >= SdAlbumFileLimit) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         const auto entry_size = Common::FS::GetSize(path); | ||||
|         ApplicationAlbumFileEntry entry{.entry = | ||||
|                                             { | ||||
|                                                 .size = entry_size, | ||||
|                                                 .hash{}, | ||||
|                                                 .datetime = file_id.date, | ||||
|                                                 .storage = file_id.storage, | ||||
|                                                 .content = contex_type, | ||||
|                                                 .unknown = 1, | ||||
|                                             }, | ||||
|                                         .datetime = file_id.date, | ||||
|                                         .unknown = {}}; | ||||
|         out_entries.push_back(entry); | ||||
|     } | ||||
|  | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const { | ||||
|     out_is_autosaving = false; | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, | ||||
|                                               std::vector<u8>& out_image, | ||||
|                                               const AlbumFileId& file_id, | ||||
|                                               const ScreenShotDecodeOption& decoder_options) const { | ||||
|     if (file_id.storage > AlbumStorage::Sd) { | ||||
|         return ResultInvalidStorage; | ||||
|     } | ||||
|  | ||||
|     if (!is_mounted) { | ||||
|         return ResultIsNotMounted; | ||||
|     } | ||||
|  | ||||
|     out_image_output = { | ||||
|         .width = 1280, | ||||
|         .height = 720, | ||||
|         .attribute = | ||||
|             { | ||||
|                 .unknown_0{}, | ||||
|                 .orientation = AlbumImageOrientation::None, | ||||
|                 .unknown_1{}, | ||||
|                 .unknown_2{}, | ||||
|             }, | ||||
|     }; | ||||
|  | ||||
|     std::filesystem::path path; | ||||
|     const auto result = GetFile(path, file_id); | ||||
|  | ||||
|     if (result.IsError()) { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); | ||||
|  | ||||
|     return LoadImage(out_image, path, static_cast<int>(out_image_output.width), | ||||
|                      +static_cast<int>(out_image_output.height), decoder_options.flags); | ||||
| } | ||||
|  | ||||
| Result AlbumManager::LoadAlbumScreenShotThumbnail( | ||||
|     LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image, | ||||
|     const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const { | ||||
|     if (file_id.storage > AlbumStorage::Sd) { | ||||
|         return ResultInvalidStorage; | ||||
|     } | ||||
|  | ||||
|     if (!is_mounted) { | ||||
|         return ResultIsNotMounted; | ||||
|     } | ||||
|  | ||||
|     out_image_output = { | ||||
|         .width = 320, | ||||
|         .height = 180, | ||||
|         .attribute = | ||||
|             { | ||||
|                 .unknown_0{}, | ||||
|                 .orientation = AlbumImageOrientation::None, | ||||
|                 .unknown_1{}, | ||||
|                 .unknown_2{}, | ||||
|             }, | ||||
|     }; | ||||
|  | ||||
|     std::filesystem::path path; | ||||
|     const auto result = GetFile(path, file_id); | ||||
|  | ||||
|     if (result.IsError()) { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); | ||||
|  | ||||
|     return LoadImage(out_image, path, static_cast<int>(out_image_output.width), | ||||
|                      +static_cast<int>(out_image_output.height), decoder_options.flags); | ||||
| } | ||||
|  | ||||
| Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { | ||||
|     const auto file = album_files.find(file_id); | ||||
|  | ||||
|     if (file == album_files.end()) { | ||||
|         return ResultFileNotFound; | ||||
|     } | ||||
|  | ||||
|     out_path = file->second; | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
| void AlbumManager::FindScreenshots() { | ||||
|     is_mounted = false; | ||||
|     album_files.clear(); | ||||
|  | ||||
|     // TODO: Swap this with a blocking operation. | ||||
|     const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir); | ||||
|     Common::FS::IterateDirEntries( | ||||
|         screenshots_dir, | ||||
|         [this](const std::filesystem::path& full_path) { | ||||
|             AlbumEntry entry; | ||||
|             if (GetAlbumEntry(entry, full_path).IsError()) { | ||||
|                 return true; | ||||
|             } | ||||
|             while (album_files.contains(entry.file_id)) { | ||||
|                 if (++entry.file_id.date.unique_id == 0) { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             album_files[entry.file_id] = full_path; | ||||
|             return true; | ||||
|         }, | ||||
|         Common::FS::DirEntryFilter::File); | ||||
|  | ||||
|     is_mounted = true; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const { | ||||
|     std::istringstream line_stream(path.filename().string()); | ||||
|     std::string date; | ||||
|     std::string application; | ||||
|     std::string time; | ||||
|  | ||||
|     // Parse filename to obtain entry properties | ||||
|     std::getline(line_stream, application, '_'); | ||||
|     std::getline(line_stream, date, '_'); | ||||
|     std::getline(line_stream, time, '_'); | ||||
|  | ||||
|     std::istringstream date_stream(date); | ||||
|     std::istringstream time_stream(time); | ||||
|     std::string year; | ||||
|     std::string month; | ||||
|     std::string day; | ||||
|     std::string hour; | ||||
|     std::string minute; | ||||
|     std::string second; | ||||
|  | ||||
|     std::getline(date_stream, year, '-'); | ||||
|     std::getline(date_stream, month, '-'); | ||||
|     std::getline(date_stream, day, '-'); | ||||
|  | ||||
|     std::getline(time_stream, hour, '-'); | ||||
|     std::getline(time_stream, minute, '-'); | ||||
|     std::getline(time_stream, second, '-'); | ||||
|  | ||||
|     try { | ||||
|         out_entry = { | ||||
|             .entry_size = 1, | ||||
|             .file_id{ | ||||
|                 .application_id = static_cast<u64>(std::stoll(application, 0, 16)), | ||||
|                 .date = | ||||
|                     { | ||||
|                         .year = static_cast<u16>(std::stoi(year)), | ||||
|                         .month = static_cast<u8>(std::stoi(month)), | ||||
|                         .day = static_cast<u8>(std::stoi(day)), | ||||
|                         .hour = static_cast<u8>(std::stoi(hour)), | ||||
|                         .minute = static_cast<u8>(std::stoi(minute)), | ||||
|                         .second = static_cast<u8>(std::stoi(second)), | ||||
|                         .unique_id = 0, | ||||
|                     }, | ||||
|                 .storage = AlbumStorage::Sd, | ||||
|                 .type = ContentType::Screenshot, | ||||
|                 .unknown = 1, | ||||
|             }, | ||||
|         }; | ||||
|     } catch (const std::invalid_argument&) { | ||||
|         return ResultUnknown; | ||||
|     } catch (const std::out_of_range&) { | ||||
|         return ResultUnknown; | ||||
|     } catch (const std::exception&) { | ||||
|         return ResultUnknown; | ||||
|     } | ||||
|  | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
| Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path, | ||||
|                                int width, int height, ScreenShotDecoderFlag flag) const { | ||||
|     if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) { | ||||
|         return ResultUnknown; | ||||
|     } | ||||
|  | ||||
|     const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read, | ||||
|                                      Common::FS::FileType::BinaryFile}; | ||||
|  | ||||
|     std::vector<u8> raw_file(db_file.GetSize()); | ||||
|     if (db_file.Read(raw_file) != raw_file.size()) { | ||||
|         return ResultUnknown; | ||||
|     } | ||||
|  | ||||
|     int filter_flag = STBIR_FILTER_DEFAULT; | ||||
|     int original_width, original_height, color_channels; | ||||
|     const auto dbi_image = | ||||
|         stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width, | ||||
|                               &original_height, &color_channels, STBI_rgb_alpha); | ||||
|  | ||||
|     if (dbi_image == nullptr) { | ||||
|         return ResultUnknown; | ||||
|     } | ||||
|  | ||||
|     switch (flag) { | ||||
|     case ScreenShotDecoderFlag::EnableFancyUpsampling: | ||||
|         filter_flag = STBIR_FILTER_TRIANGLE; | ||||
|         break; | ||||
|     case ScreenShotDecoderFlag::EnableBlockSmoothing: | ||||
|         filter_flag = STBIR_FILTER_BOX; | ||||
|         break; | ||||
|     default: | ||||
|         filter_flag = STBIR_FILTER_DEFAULT; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width, | ||||
|                             height, 0, STBI_rgb_alpha, 3, filter_flag); | ||||
|  | ||||
|     return ResultSuccess; | ||||
| } | ||||
| } // namespace Service::Capture | ||||
							
								
								
									
										72
									
								
								src/core/hle/service/caps/caps_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/core/hle/service/caps/caps_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <unordered_map> | ||||
|  | ||||
| #include "common/fs/fs.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/caps/caps_types.h" | ||||
|  | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
|  | ||||
| namespace std { | ||||
| // Hash used to create lists from AlbumFileId data | ||||
| template <> | ||||
| struct hash<Service::Capture::AlbumFileId> { | ||||
|     size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept { | ||||
|         u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.date.month) << 7); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.date.day) << 6); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.date.second) << 3); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2); | ||||
|         hash_value ^= (static_cast<u64>(pad_id.storage) << 1); | ||||
|         hash_value ^= static_cast<u64>(pad_id.type); | ||||
|         return static_cast<size_t>(hash_value); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace std | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| class AlbumManager { | ||||
| public: | ||||
|     explicit AlbumManager(); | ||||
|     ~AlbumManager(); | ||||
|  | ||||
|     Result DeleteAlbumFile(const AlbumFileId& file_id); | ||||
|     Result IsAlbumMounted(AlbumStorage storage); | ||||
|     Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, | ||||
|                             u8 flags) const; | ||||
|     Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, | ||||
|                             ContentType contex_type, AlbumFileDateTime start_date, | ||||
|                             AlbumFileDateTime end_date, u64 aruid) const; | ||||
|     Result GetAutoSavingStorage(bool& out_is_autosaving) const; | ||||
|     Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, | ||||
|                                     std::vector<u8>& out_image, const AlbumFileId& file_id, | ||||
|                                     const ScreenShotDecodeOption& decoder_options) const; | ||||
|     Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output, | ||||
|                                         std::vector<u8>& out_image, const AlbumFileId& file_id, | ||||
|                                         const ScreenShotDecodeOption& decoder_options) const; | ||||
|  | ||||
| private: | ||||
|     static constexpr std::size_t NandAlbumFileLimit = 1000; | ||||
|     static constexpr std::size_t SdAlbumFileLimit = 10000; | ||||
|  | ||||
|     void FindScreenshots(); | ||||
|     Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const; | ||||
|     Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; | ||||
|     Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, | ||||
|                      int height, ScreenShotDecoderFlag flag) const; | ||||
|  | ||||
|     bool is_mounted{}; | ||||
|     std::unordered_map<AlbumFileId, std::filesystem::path> album_files; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Capture | ||||
							
								
								
									
										35
									
								
								src/core/hle/service/caps/caps_result.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/core/hle/service/caps/caps_result.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/result.h" | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3); | ||||
| constexpr Result ResultUnknown5(ErrorModule::Capture, 5); | ||||
| constexpr Result ResultUnknown6(ErrorModule::Capture, 6); | ||||
| constexpr Result ResultUnknown7(ErrorModule::Capture, 7); | ||||
| constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); | ||||
| constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); | ||||
| constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); | ||||
| constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); | ||||
| constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); | ||||
| constexpr Result ResultUnknown22(ErrorModule::Capture, 22); | ||||
| constexpr Result ResultFileNotFound(ErrorModule::Capture, 23); | ||||
| constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24); | ||||
| constexpr Result ResultUnknown25(ErrorModule::Capture, 25); | ||||
| constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30); | ||||
| constexpr Result ResultUnknown810(ErrorModule::Capture, 810); | ||||
| constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024); | ||||
| constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202); | ||||
| constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203); | ||||
| constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401); | ||||
| constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701); | ||||
| constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801); | ||||
| constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802); | ||||
| constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803); | ||||
| constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804); | ||||
|  | ||||
| } // namespace Service::Capture | ||||
| @@ -5,7 +5,8 @@ | ||||
|  | ||||
| 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 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {1, nullptr, "CaptureRawImage"}, | ||||
| @@ -34,6 +35,6 @@ CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} { | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
|  | ||||
| CAPS_SC::~CAPS_SC() = default; | ||||
| IScreenShotControlService::~IScreenShotControlService() = default; | ||||
|  | ||||
| } // namespace Service::Capture | ||||
|   | ||||
| @@ -11,10 +11,10 @@ class System; | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| class CAPS_SC final : public ServiceFramework<CAPS_SC> { | ||||
| class IScreenShotControlService final : public ServiceFramework<IScreenShotControlService> { | ||||
| public: | ||||
|     explicit CAPS_SC(Core::System& system_); | ||||
|     ~CAPS_SC() override; | ||||
|     explicit IScreenShotControlService(Core::System& system_); | ||||
|     ~IScreenShotControlService() override; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Capture | ||||
|   | ||||
| @@ -5,7 +5,8 @@ | ||||
|  | ||||
| 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 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {201, nullptr, "SaveScreenShot"}, | ||||
| @@ -21,6 +22,6 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} { | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
|  | ||||
| CAPS_SS::~CAPS_SS() = default; | ||||
| IScreenShotService::~IScreenShotService() = default; | ||||
|  | ||||
| } // namespace Service::Capture | ||||
|   | ||||
| @@ -11,10 +11,10 @@ class System; | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| class CAPS_SS final : public ServiceFramework<CAPS_SS> { | ||||
| class IScreenShotService final : public ServiceFramework<IScreenShotService> { | ||||
| public: | ||||
|     explicit CAPS_SS(Core::System& system_); | ||||
|     ~CAPS_SS() override; | ||||
|     explicit IScreenShotService(Core::System& system_); | ||||
|     ~IScreenShotService() override; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Capture | ||||
|   | ||||
| @@ -7,10 +7,11 @@ | ||||
|  | ||||
| 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 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {201, nullptr, "SaveScreenShot"}, | ||||
|         {203, nullptr, "SaveScreenShotEx0"}, | ||||
|         {205, nullptr, "SaveScreenShotEx1"}, | ||||
| @@ -21,9 +22,9 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} { | ||||
|     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}; | ||||
|     const auto library_version{rp.Pop<u64>()}; | ||||
|     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||
|   | ||||
| @@ -11,10 +11,10 @@ class System; | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| class CAPS_SU final : public ServiceFramework<CAPS_SU> { | ||||
| class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { | ||||
| public: | ||||
|     explicit CAPS_SU(Core::System& system_); | ||||
|     ~CAPS_SU() override; | ||||
|     explicit IScreenShotApplicationService(Core::System& system_); | ||||
|     ~IScreenShotApplicationService() override; | ||||
|  | ||||
| private: | ||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||
|   | ||||
							
								
								
									
										184
									
								
								src/core/hle/service/caps/caps_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/core/hle/service/caps/caps_types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| // This is nn::album::ImageOrientation | ||||
| enum class AlbumImageOrientation { | ||||
|     None, | ||||
|     Rotate90, | ||||
|     Rotate180, | ||||
|     Rotate270, | ||||
| }; | ||||
|  | ||||
| // This is nn::album::AlbumReportOption | ||||
| enum class AlbumReportOption : s32 { | ||||
|     Disable, | ||||
|     Enable, | ||||
| }; | ||||
|  | ||||
| enum class ContentType : u8 { | ||||
|     Screenshot = 0, | ||||
|     Movie = 1, | ||||
|     ExtraMovie = 3, | ||||
| }; | ||||
|  | ||||
| enum class AlbumStorage : u8 { | ||||
|     Nand, | ||||
|     Sd, | ||||
| }; | ||||
|  | ||||
| enum class ScreenShotDecoderFlag : u64 { | ||||
|     None = 0, | ||||
|     EnableFancyUpsampling = 1 << 0, | ||||
|     EnableBlockSmoothing = 1 << 1, | ||||
| }; | ||||
|  | ||||
| // This is nn::capsrv::AlbumFileDateTime | ||||
| struct AlbumFileDateTime { | ||||
|     u16 year{}; | ||||
|     u8 month{}; | ||||
|     u8 day{}; | ||||
|     u8 hour{}; | ||||
|     u8 minute{}; | ||||
|     u8 second{}; | ||||
|     u8 unique_id{}; | ||||
|  | ||||
|     friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default; | ||||
|     friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { | ||||
|         if (a.year > b.year) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.month > b.month) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.day > b.day) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.hour > b.hour) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.minute > b.minute) { | ||||
|             return true; | ||||
|         } | ||||
|         return a.second > b.second; | ||||
|     }; | ||||
|     friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { | ||||
|         if (a.year < b.year) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.month < b.month) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.day < b.day) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.hour < b.hour) { | ||||
|             return true; | ||||
|         } | ||||
|         if (a.minute < b.minute) { | ||||
|             return true; | ||||
|         } | ||||
|         return a.second < b.second; | ||||
|     }; | ||||
| }; | ||||
| static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size."); | ||||
|  | ||||
| // This is nn::album::AlbumEntry | ||||
| struct AlbumFileEntry { | ||||
|     u64 size{}; // Size of the entry | ||||
|     u64 hash{}; // AES256 with hardcoded key over AlbumEntry | ||||
|     AlbumFileDateTime datetime{}; | ||||
|     AlbumStorage storage{}; | ||||
|     ContentType content{}; | ||||
|     INSERT_PADDING_BYTES(5); | ||||
|     u8 unknown{}; // Set to 1 on official SW | ||||
| }; | ||||
| static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size."); | ||||
|  | ||||
| struct AlbumFileId { | ||||
|     u64 application_id{}; | ||||
|     AlbumFileDateTime date{}; | ||||
|     AlbumStorage storage{}; | ||||
|     ContentType type{}; | ||||
|     INSERT_PADDING_BYTES(0x5); | ||||
|     u8 unknown{}; | ||||
|  | ||||
|     friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default; | ||||
| }; | ||||
| static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size"); | ||||
|  | ||||
| // This is nn::capsrv::AlbumEntry | ||||
| struct AlbumEntry { | ||||
|     u64 entry_size{}; | ||||
|     AlbumFileId file_id{}; | ||||
| }; | ||||
| static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size."); | ||||
|  | ||||
| // This is nn::capsrv::ApplicationAlbumEntry | ||||
| struct ApplicationAlbumEntry { | ||||
|     u64 size{}; // Size of the entry | ||||
|     u64 hash{}; // AES256 with hardcoded key over AlbumEntry | ||||
|     AlbumFileDateTime datetime{}; | ||||
|     AlbumStorage storage{}; | ||||
|     ContentType content{}; | ||||
|     INSERT_PADDING_BYTES(5); | ||||
|     u8 unknown{1}; // Set to 1 on official SW | ||||
| }; | ||||
| static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size."); | ||||
|  | ||||
| // This is nn::capsrv::ApplicationAlbumFileEntry | ||||
| struct ApplicationAlbumFileEntry { | ||||
|     ApplicationAlbumEntry entry{}; | ||||
|     AlbumFileDateTime datetime{}; | ||||
|     u64 unknown{}; | ||||
| }; | ||||
| static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, | ||||
|               "ApplicationAlbumFileEntry has incorrect size."); | ||||
|  | ||||
| struct ApplicationData { | ||||
|     std::array<u8, 0x400> data{}; | ||||
|     u32 data_size{}; | ||||
| }; | ||||
| static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size"); | ||||
|  | ||||
| struct ScreenShotAttribute { | ||||
|     u32 unknown_0{}; | ||||
|     AlbumImageOrientation orientation{}; | ||||
|     u32 unknown_1{}; | ||||
|     u32 unknown_2{}; | ||||
|     INSERT_PADDING_BYTES(0x30); | ||||
| }; | ||||
| static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size"); | ||||
|  | ||||
| struct ScreenShotDecodeOption { | ||||
|     ScreenShotDecoderFlag flags{}; | ||||
|     INSERT_PADDING_BYTES(0x18); | ||||
| }; | ||||
| static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size"); | ||||
|  | ||||
| struct LoadAlbumScreenShotImageOutput { | ||||
|     s64 width{}; | ||||
|     s64 height{}; | ||||
|     ScreenShotAttribute attribute{}; | ||||
|     INSERT_PADDING_BYTES(0x400); | ||||
| }; | ||||
| static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450, | ||||
|               "LoadAlbumScreenShotImageOutput is an invalid size"); | ||||
|  | ||||
| struct LoadAlbumScreenShotImageOutputForApplication { | ||||
|     s64 width{}; | ||||
|     s64 height{}; | ||||
|     ScreenShotAttribute attribute{}; | ||||
|     ApplicationData data{}; | ||||
|     INSERT_PADDING_BYTES(0xAC); | ||||
| }; | ||||
| static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500, | ||||
|               "LoadAlbumScreenShotImageOutput is an invalid size"); | ||||
|  | ||||
| } // namespace Service::Capture | ||||
| @@ -2,45 +2,29 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #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/ipc_helpers.h" | ||||
|  | ||||
| namespace Service::Capture { | ||||
|  | ||||
| class IAlbumAccessorApplicationSession final | ||||
|     : public ServiceFramework<IAlbumAccessorApplicationSession> { | ||||
| public: | ||||
|     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"} { | ||||
| IAlbumApplicationService::IAlbumApplicationService(Core::System& system_, | ||||
|                                                    std::shared_ptr<AlbumManager> album_manager) | ||||
|     : ServiceFramework{system_, "caps:u"}, manager{album_manager} { | ||||
|     // clang-format off | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, | ||||
|         {103, nullptr, "DeleteAlbumContentsFileForApplication"}, | ||||
|         {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, | ||||
|         {32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"}, | ||||
|         {103, nullptr, "DeleteAlbumFileByAruid"}, | ||||
|         {104, nullptr, "GetAlbumFileSizeByAruid"}, | ||||
|         {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, | ||||
|         {110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"}, | ||||
|         {120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"}, | ||||
|         {130, nullptr, "PrecheckToCreateContentsForApplication"}, | ||||
|         {110, nullptr, "LoadAlbumScreenShotImageByAruid"}, | ||||
|         {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"}, | ||||
|         {130, nullptr, "PrecheckToCreateContentsByAruid"}, | ||||
|         {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, | ||||
|         {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, | ||||
|         {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, | ||||
|         {142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, | ||||
|         {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, | ||||
|         {144, nullptr, "GetAllAlbumFileList3AaeAruid"}, | ||||
|         {60002, nullptr, "OpenAccessorSessionForApplication"}, | ||||
| @@ -50,9 +34,9 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} { | ||||
|     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}; | ||||
|     const auto library_version{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); | ||||
| } | ||||
|  | ||||
| void CAPS_U::GetAlbumContentsFileListForApplication(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). | ||||
| void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto pid{rp.Pop<s32>()}; | ||||
|     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 applet_resource_user_id{rp.Pop<u64>()}; | ||||
|  | ||||
|     // TODO: Update this when we implement the album. | ||||
|     // Currently we do not have a method of accessing album entries, set this to 0 for now. | ||||
|     constexpr u32 total_entries_1{}; | ||||
|     constexpr u32 total_entries_2{}; | ||||
|     LOG_WARNING(Service_Capture, | ||||
|                 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " | ||||
|                 "end_posix_time={}, applet_resource_user_id={}", | ||||
|                 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id); | ||||
|  | ||||
|     LOG_WARNING( | ||||
|         Service_Capture, | ||||
|         "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " | ||||
|         "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}", | ||||
|         pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, | ||||
|         total_entries_1, total_entries_2); | ||||
|     // TODO: Translate posix to DateTime | ||||
|  | ||||
|     std::vector<ApplicationAlbumFileEntry> entries; | ||||
|     const Result result = | ||||
|         manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id); | ||||
|  | ||||
|     if (!entries.empty()) { | ||||
|         ctx.WriteBuffer(entries); | ||||
|     } | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push(total_entries_1); | ||||
|     rb.Push(total_entries_2); | ||||
|     rb.Push(result); | ||||
|     rb.Push<u64>(entries.size()); | ||||
| } | ||||
|  | ||||
| void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { | ||||
|     GetAlbumContentsFileListForApplication(ctx); | ||||
| void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& 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 | ||||
|   | ||||
| @@ -10,16 +10,20 @@ class System; | ||||
| } | ||||
|  | ||||
| namespace Service::Capture { | ||||
| class AlbumManager; | ||||
|  | ||||
| class CAPS_U final : public ServiceFramework<CAPS_U> { | ||||
| class IAlbumApplicationService final : public ServiceFramework<IAlbumApplicationService> { | ||||
| public: | ||||
|     explicit CAPS_U(Core::System& system_); | ||||
|     ~CAPS_U() override; | ||||
|     explicit IAlbumApplicationService(Core::System& system_, | ||||
|                                       std::shared_ptr<AlbumManager> album_manager); | ||||
|     ~IAlbumApplicationService() override; | ||||
|  | ||||
| private: | ||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||
|     void GetAlbumContentsFileListForApplication(HLERequestContext& ctx); | ||||
|     void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx); | ||||
|     void GetAlbumFileList3AaeAruid(HLERequestContext& ctx); | ||||
|  | ||||
|     std::shared_ptr<AlbumManager> manager = nullptr; | ||||
| }; | ||||
|  | ||||
| } // 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_) | ||||
|     : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} { | ||||
|     // clang-format off | ||||
| @@ -569,7 +579,7 @@ IGeneralService::IGeneralService(Core::System& system_) | ||||
|         {19, nullptr, "SetEthernetCommunicationEnabled"}, | ||||
|         {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"}, | ||||
|         {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"}, | ||||
|         {22, nullptr, "IsAnyForegroundRequestAccepted"}, | ||||
|         {22, &IGeneralService::IsAnyForegroundRequestAccepted, "IsAnyForegroundRequestAccepted"}, | ||||
|         {23, nullptr, "PutToSleep"}, | ||||
|         {24, nullptr, "WakeUp"}, | ||||
|         {25, nullptr, "GetSsidListVersion"}, | ||||
|   | ||||
| @@ -35,6 +35,7 @@ private: | ||||
|     void GetInternetConnectionStatus(HLERequestContext& ctx); | ||||
|     void IsEthernetCommunicationEnabled(HLERequestContext& ctx); | ||||
|     void IsAnyInternetRequestAccepted(HLERequestContext& ctx); | ||||
|     void IsAnyForegroundRequestAccepted(HLERequestContext& ctx); | ||||
|  | ||||
|     Network::RoomNetwork& network; | ||||
| }; | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include "core/file_sys/control_metadata.h" | ||||
| #include "core/file_sys/patch_manager.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/ipc_helpers.h" | ||||
| #include "core/hle/service/ns/errors.h" | ||||
| @@ -502,8 +503,8 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_) | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {11, nullptr, "CalculateApplicationOccupiedSize"}, | ||||
|         {43, nullptr, "CheckSdCardMountStatus"}, | ||||
|         {47, nullptr, "GetTotalSpaceSize"}, | ||||
|         {48, nullptr, "GetFreeSpaceSize"}, | ||||
|         {47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"}, | ||||
|         {48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"}, | ||||
|         {600, nullptr, "CountApplicationContentMeta"}, | ||||
|         {601, nullptr, "ListApplicationContentMetaStatus"}, | ||||
|         {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, | ||||
| @@ -516,6 +517,28 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_) | ||||
|  | ||||
| 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_) | ||||
|     : ServiceFramework{system_, "IDocumentInterface"} { | ||||
|     // clang-format off | ||||
|   | ||||
| @@ -48,6 +48,10 @@ class IContentManagementInterface final : public ServiceFramework<IContentManage | ||||
| public: | ||||
|     explicit IContentManagementInterface(Core::System& system_); | ||||
|     ~IContentManagementInterface() override; | ||||
|  | ||||
| private: | ||||
|     void GetTotalSpaceSize(HLERequestContext& ctx); | ||||
|     void GetFreeSpaceSize(HLERequestContext& ctx); | ||||
| }; | ||||
|  | ||||
| class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { | ||||
|   | ||||
| @@ -33,7 +33,7 @@ public: | ||||
|             {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, | ||||
|             {1002, nullptr, "ConfirmLaunchApplicationPermission"}, | ||||
|             {1003, nullptr, "ConfirmResumeApplicationPermission"}, | ||||
|             {1004, nullptr, "ConfirmSnsPostPermission"}, | ||||
|             {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"}, | ||||
|             {1005, nullptr, "ConfirmSystemSettingsPermission"}, | ||||
|             {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"}, | ||||
|             {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, | ||||
| @@ -236,6 +236,13 @@ private: | ||||
|         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) { | ||||
|         const bool is_temporary_unlocked = false; | ||||
|  | ||||
|   | ||||
| @@ -1560,6 +1560,7 @@ void GMainWindow::ConnectMenuEvents() { | ||||
|     // Tools | ||||
|     connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, | ||||
|                                                 ReinitializeKeyBehavior::Warning)); | ||||
|     connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum); | ||||
|     connect_menu(ui->action_Load_Cabinet_Nickname_Owner, | ||||
|                  [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); }); | ||||
|     connect_menu(ui->action_Load_Cabinet_Eraser, | ||||
| @@ -1597,6 +1598,7 @@ void GMainWindow::UpdateMenuState() { | ||||
|     }; | ||||
|  | ||||
|     const std::array applet_actions{ | ||||
|         ui->action_Load_Album, | ||||
|         ui->action_Load_Cabinet_Nickname_Owner, | ||||
|         ui->action_Load_Cabinet_Eraser, | ||||
|         ui->action_Load_Cabinet_Restorer, | ||||
| @@ -4224,6 +4226,29 @@ void GMainWindow::OnToggleStatusBar() { | ||||
|     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) { | ||||
|     constexpr u64 CabinetId = 0x0100000000001002ull; | ||||
|     auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); | ||||
|   | ||||
| @@ -374,6 +374,7 @@ private slots: | ||||
|     void ResetWindowSize720(); | ||||
|     void ResetWindowSize900(); | ||||
|     void ResetWindowSize1080(); | ||||
|     void OnAlbum(); | ||||
|     void OnCabinet(Service::NFP::CabinetMode mode); | ||||
|     void OnMiiEdit(); | ||||
|     void OnCaptureScreenshot(); | ||||
|   | ||||
| @@ -160,6 +160,7 @@ | ||||
|     <addaction name="action_Verify_installed_contents"/> | ||||
|     <addaction name="separator"/> | ||||
|     <addaction name="menu_cabinet_applet"/> | ||||
|     <addaction name="action_Load_Album"/> | ||||
|     <addaction name="action_Load_Mii_Edit"/> | ||||
|     <addaction name="separator"/> | ||||
|     <addaction name="action_Capture_Screenshot"/> | ||||
| @@ -380,6 +381,11 @@ | ||||
|     <string>&Capture Screenshot</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="action_Load_Album"> | ||||
|     <property name="text"> | ||||
|       <string>Open &Album</string> | ||||
|     </property> | ||||
|   </action> | ||||
|   <action name="action_Load_Cabinet_Nickname_Owner"> | ||||
|    <property name="text"> | ||||
|     <string>&Set Nickname and Owner</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user