[graphics/digikam] /: Update Libraw to last 20072026 snapshot: add support of Sony ARW6 CRAW HQ, Sony ILCE-7M5, and Canon R50 V camera.

Gilles Caulier <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit a153fdc1257207416a5db61de0d3840aeac2b680 by Gilles Caulier.
Committed on 20/07/2026 at 09:14.
Pushed by cgilles into branch 'master'.

Update Libraw to last 20072026 snapshot: add support of Sony ARW6 CRAW HQ, Sony ILCE-7M5, and Canon R50 V camera.

M  +2    -1    NEWS
M  +2    -2    core/app/views/stack/welcomepageview_features.cpp
M  +1    -0    core/libs/rawengine/CMakeLists.txt
M  +2    -0    core/libs/rawengine/libraw/internal/libraw_cameraids.h
M  +1    -0    core/libs/rawengine/libraw/internal/libraw_internal_funcs.h
M  +2    -2    core/libs/rawengine/libraw/libraw_manifest.txt
A  +1618 -0    core/libs/rawengine/libraw/src/decoders/sony_arw6.cpp  *
M  +2    -1    core/libs/rawengine/libraw/src/metadata/canon.cpp
M  +1    -1    core/libs/rawengine/libraw/src/metadata/identify.cpp
M  +2    -0    core/libs/rawengine/libraw/src/metadata/normalize_model.cpp
M  +4    -1    core/libs/rawengine/libraw/src/metadata/sony.cpp
M  +11   -0    core/libs/rawengine/libraw/src/metadata/tiff.cpp
M  +2    -0    core/libs/rawengine/libraw/src/tables/cameralist.cpp
M  +5    -1    core/libs/rawengine/libraw/src/tables/colordata.cpp
M  +5    -0    core/libs/rawengine/libraw/src/utils/decoder_info.cpp
M  +11   -0    core/libs/rawengine/libraw/src/utils/open.cpp

The files marked with a * at the end have a non valid license. Please read: https://community.kde.org/Policies/Licensing_Policy and use the headers which are listed at that page.


https://invent.kde.org/graphics/digikam/-/commit/a153fdc1257207416a5db61de0d3840aeac2b680

diff --git a/NEWS b/NEWS
index fac3e1a8a8..f0fdeaf6fe 100644
--- a/NEWS
+++ b/NEWS
@@ -16,7 +16,8 @@ Bundles component versions:
 | macOS Qt5     | 5.15.18    | 5.116      | 4.13     | 8.0.1     | 1.20.2     | 13.59 (*) | 0.28.8     | 20260716 (*) | 20260405     | Monterey + Macports |
 | macOS Qt6     | 6.11.0     | 6.26.0     | 4.13     | 8.1.0     | 1.21.2     | 13.59 (*) | 0.28.8     | 20260716 (*) |    -         | Tathoe + Macports   |
 
-Icon-View: Improve filename matching for timelapse/burst grouping items.
+Icon-View  : Improve filename matching for timelapse/burst grouping items.
+Raw Support: Add support of Sony ARW6 CRAW HQ, Sony ILCE-7M5, and Canon R50 V.
 
 *****************************************************************************************************
 
diff --git a/core/app/views/stack/welcomepageview_features.cpp b/core/app/views/stack/welcomepageview_features.cpp
index b18b558b0a..5e252f4d2b 100644
--- a/core/app/views/stack/welcomepageview_features.cpp
+++ b/core/app/views/stack/welcomepageview_features.cpp
@@ -90,7 +90,7 @@ QString WelcomePageView::featuresTabContent() const
     newFeatures << i18n("Update internal RAW engine to last Libraw snapshot 2026-04-06.");
     newFeatures << i18n("New RAW camera supported:")
                 + appendSubList(QStringList()
-                    << i18n("Canon EOS R1, EOS R5 Mark II, EOS R5 C, EOS R6 Mark II, EOS R8, EOS R50, EOS R100, EOS Ra Canon EOS Kiss M2;")
+                    << i18n("Canon R50 V, Canon EOS R1, EOS R5 Mark II, EOS R5 C, EOS R6 Mark II, EOS R8, EOS R50, EOS R100, EOS Ra Canon EOS Kiss M2;")
                     << i18n("Fujifilm X-T50, GFX 100S II, GFX100-II, X-T5, X-S20, X-H2, X-H2S ;")
                     << i18n("Hasselblad  CFV-50c, CFV-100c, X2D-100c ;")
                     << i18n("Leica Q3 43, D-Lux8, SL3, Q3, M11 Monochrom ;")
@@ -98,7 +98,7 @@ QString WelcomePageView::featuresTabContent() const
                     << i18n("Olympus/OM System OM-1 Mark II, TG-7, OM-5 ;")
                     << i18n("Panasonic GH7, S9, DC-G9 II, DC-ZS200D / ZS220D, DC-TZ200D / TZ202D / TZ220D, DC-S5-II, DC-GH6 ;")
                     << i18n("Pentax KF, K III Monochrome ;")
-                    << i18n("Sony ZV-E10M2, UMC-R10C, A9-III, ILX-LR1, A7C-II, A7CR, ILCE-6700,  ZV-1M2, ZV-E1, ILCE-7RM5 (A7R-V), ILME-FX30, A1 ;")
+                    << i18n("Sony Sony ARW6 CRAW HQ, Sony ILCE-7M, VZV-E10M2, UMC-R10C, A9-III, ILX-LR1, A7C-II, A7CR, ILCE-6700,  ZV-1M2, ZV-E1, ILCE-7RM5 (A7R-V), ILME-FX30, A1 ;")
                     << i18n("Multiple DJI and Skydio drones ;")
                     << i18n("Multiple smartphones with DNG format recorded.")
                 );
diff --git a/core/libs/rawengine/CMakeLists.txt b/core/libs/rawengine/CMakeLists.txt
index 4f2f2e6abc..e048855c34 100644
--- a/core/libs/rawengine/CMakeLists.txt
+++ b/core/libs/rawengine/CMakeLists.txt
@@ -104,6 +104,7 @@ set(libraw_LIB_SRCS
     ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decoders/pana8.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decoders/decoders_dcraw.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decoders/sonycc.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decoders/sony_arw6.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decompressors/losslessjpeg.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decoders/decoders_libraw_dcrdefs.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/libraw/src/decoders/decoders_libraw.cpp
diff --git a/core/libs/rawengine/libraw/internal/libraw_cameraids.h b/core/libs/rawengine/libraw/internal/libraw_cameraids.h
index 4a55db346b..0367ef3a9f 100644
--- a/core/libs/rawengine/libraw/internal/libraw_cameraids.h
+++ b/core/libs/rawengine/libraw/internal/libraw_cameraids.h
@@ -94,6 +94,7 @@ it under the terms of the one of two licenses as you choose:
 #define CanonID_EOS_R7            (0x80000000ULL + 0x464ULL)
 #define CanonID_EOS_R10           (0x80000000ULL + 0x465ULL)
 #define CanonID_EOS_M50_Mark_II   (0x80000000ULL + 0x468ULL)
+#define CanonID_EOS_R50_V         (0x80000000ULL + 0x516ULL)
 #define CanonID_EOS_R50           (0x80000000ULL + 0x480ULL)
 #define CanonID_EOS_R6m2          (0x80000000ULL + 0x481ULL)
 #define CanonID_EOS_R8            (0x80000000ULL + 0x487ULL)
@@ -344,4 +345,5 @@ it under the terms of the one of two licenses as you choose:
 #define SonyID_ZV_E10M2         0x18fULL
 #define SonyID_ILME_FX2         0x196ULL
 #define SonyID_ILCE_1M2         0x190ULL
+#define SonyID_ILCE_7M5         0x197ULL
 #endif
diff --git a/core/libs/rawengine/libraw/internal/libraw_internal_funcs.h b/core/libs/rawengine/libraw/internal/libraw_internal_funcs.h
index 7cb2aa780d..f30c6365d8 100644
--- a/core/libs/rawengine/libraw/internal/libraw_internal_funcs.h
+++ b/core/libs/rawengine/libraw/internal/libraw_internal_funcs.h
@@ -282,6 +282,7 @@ it under the terms of the one of two licenses as you choose:
 	void        sony_load_raw();
 	void        sony_arw_load_raw();
 	void        sony_arw2_load_raw();
+	void        sony_arw6_load_raw();
 	void        sony_arq_load_raw();
 	void        sony_ljpeg_load_raw();
 	void        sony_ycbcr_load_raw();
diff --git a/core/libs/rawengine/libraw/libraw_manifest.txt b/core/libs/rawengine/libraw/libraw_manifest.txt
index 86783bba78..b392fcc00f 100644
--- a/core/libs/rawengine/libraw/libraw_manifest.txt
+++ b/core/libs/rawengine/libraw/libraw_manifest.txt
@@ -1,2 +1,2 @@
-+LIBRAW Snapshot 2026-07-16
-libraw:87241b45d8c8178247faca4aa8e6a1896b0b1eeb
++LIBRAW Snapshot 2026-07-20
+libraw:e419de08001de28ae6988ecb22df47e52b9c5eaa
diff --git a/core/libs/rawengine/libraw/src/decoders/sony_arw6.cpp b/core/libs/rawengine/libraw/src/decoders/sony_arw6.cpp
new file mode 100644
index 0000000000..1c47a7390a
--- /dev/null
+++ b/core/libs/rawengine/libraw/src/decoders/sony_arw6.cpp
@@ -0,0 +1,1618 @@
+/* -*- C++ -*-
+ * Copyright 2026 LibRaw LLC ([email protected])
+ * Copyright (C) 2026 Jiang Yaogeng (Sony ARW6 CRAW HQ decoder;
+ *   code generated with assistance from GLM-5)
+ *
+ LibRaw is free software; you can redistribute it and/or modify
+ it under the terms of the one of two licenses as you choose:
+
+1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
+   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
+
+2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
+
+ */
+
+#include "../../internal/dcraw_defs.h"
+
+#include <algorithm>
+#include <stdint.h>
+#include <string.h>
+#include <vector>
+
+namespace
+{
+const int SONY_ARW6_STREAM_OFFSET = 0x200;
+const int SONY_ARW6_INTERNAL_BIAS = 2048;
+const size_t SONY_ARW6_MAX_PLANE_SAMPLES = size_t(128) * 1024 * 1024;
+const INT64 SONY_ARW6_WORKING_BYTES_PER_TILE_PIXEL = 24;
+
+static inline int sony_arw6_align_up(int value, int multiple)
+{
+  return ((value + multiple - 1) / multiple) * multiple;
+}
+
+static inline INT64 sony_arw6_memory_limit_bytes(unsigned max_raw_memory_mb)
+{
+  return INT64(max_raw_memory_mb) * INT64(1024 * 1024);
+}
+
+static inline uint16_t sony_arw6_be16(const uchar *p)
+{
+  return uint16_t((uint16_t(p[0]) << 8) | p[1]);
+}
+
+static inline uint32_t sony_arw6_be32(const uchar *p)
+{
+  return (uint32_t(p[0]) << 24) | (uint32_t(p[1]) << 16) |
+         (uint32_t(p[2]) << 8) | uint32_t(p[3]);
+}
+
+static inline uint32_t sony_arw6_le32(const uchar *p)
+{
+  return (uint32_t(p[3]) << 24) | (uint32_t(p[2]) << 16) |
+         (uint32_t(p[1]) << 8) | uint32_t(p[0]);
+}
+
+static inline void sony_arw6_require(bool cond)
+{
+  if (!cond)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+}
+
+static inline int32_t sony_arw6_floor_shift(int64_t x, int bits)
+{
+  if (bits <= 0)
+    return int32_t(x);
+  const int64_t d = int64_t(1) << bits;
+  return int32_t(x >= 0 ? x >> bits : -(((-x) + d - 1) >> bits));
+}
+
+static inline int32_t sony_arw6_sign16(int32_t x)
+{
+  x &= 0xffff;
+  return x >= 0x8000 ? x - 0x10000 : x;
+}
+
+static inline int32_t sony_arw6_edge_detail(int32_t x, bool odd_mode)
+{
+  const int32_t signed_half_step = x > 0 ? 1 : (x < 0 ? -1 : 0);
+  const bool is_odd = (x % 2) != 0;
+  const bool use_half_step =
+      odd_mode ? is_odd : (x != 0 && !is_odd);
+  return 2 * x + (use_half_step ? signed_half_step : 0);
+}
+
+static const ushort sony_arw6_llvc3_curve[4096] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+  64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+  96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+  112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+  128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+  144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+  160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+  176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+  192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+  208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+  224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+  240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+  256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,
+  272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
+  288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303,
+  304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
+  320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335,
+  336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351,
+  352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367,
+  368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383,
+  384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
+  400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415,
+  416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431,
+  432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447,
+  448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463,
+  464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
+  480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495,
+  496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511,
+  512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527,
+  528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543,
+  544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559,
+  560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575,
+  576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591,
+  592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607,
+  608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623,
+  624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639,
+  640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655,
+  656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671,
+  672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687,
+  688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703,
+  704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719,
+  720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735,
+  736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751,
+  752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767,
+  768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783,
+  784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799,
+  800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815,
+  816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831,
+  832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847,
+  848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863,
+  864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879,
+  880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895,
+  896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911,
+  912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927,
+  928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943,
+  944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959,
+  960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975,
+  976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991,
+  992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
+  1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
+  1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039,
+  1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055,
+  1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071,
+  1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087,
+  1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103,
+  1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119,
+  1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135,
+  1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151,
+  1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167,
+  1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183,
+  1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199,
+  1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215,
+  1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231,
+  1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247,
+  1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263,
+  1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279,
+  1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295,
+  1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311,
+  1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327,
+  1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343,
+  1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359,
+  1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375,
+  1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391,
+  1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407,
+  1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423,
+  1424, 1425, 1426, 1427, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1438, 1439, 1440, 1441,
+  1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1455, 1456, 1457, 1458,
+  1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474,
+  1475, 1476, 1477, 1478, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1489, 1490, 1491, 1492,
+  1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508,
+  1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1522, 1523, 1524, 1525,
+  1526, 1527, 1529, 1530, 1531, 1532, 1534, 1535, 1536, 1537, 1538, 1539, 1541, 1542, 1543, 1544,
+  1545, 1546, 1548, 1549, 1550, 1551, 1553, 1554, 1555, 1556, 1558, 1559, 1561, 1562, 1563, 1565,
+  1566, 1567, 1568, 1569, 1571, 1572, 1573, 1574, 1575, 1576, 1578, 1579, 1580, 1581, 1583, 1584,
+  1585, 1586, 1588, 1589, 1590, 1591, 1593, 1594, 1595, 1596, 1598, 1599, 1601, 1602, 1603, 1605,
+  1606, 1607, 1608, 1609, 1611, 1612, 1613, 1614, 1615, 1616, 1618, 1619, 1621, 1622, 1623, 1625,
+  1626, 1627, 1629, 1630, 1631, 1632, 1634, 1635, 1636, 1637, 1639, 1640, 1641, 1642, 1644, 1645,
+  1646, 1647, 1649, 1650, 1651, 1652, 1654, 1655, 1656, 1657, 1659, 1660, 1662, 1663, 1664, 1666,
+  1667, 1668, 1670, 1671, 1673, 1674, 1675, 1677, 1678, 1680, 1681, 1683, 1685, 1686, 1688, 1689,
+  1691, 1692, 1694, 1695, 1697, 1698, 1699, 1701, 1702, 1704, 1705, 1707, 1709, 1710, 1712, 1713,
+  1715, 1716, 1718, 1719, 1720, 1721, 1723, 1724, 1725, 1727, 1728, 1730, 1731, 1733, 1734, 1736,
+  1737, 1739, 1740, 1742, 1743, 1745, 1746, 1748, 1749, 1750, 1752, 1753, 1755, 1756, 1757, 1759,
+  1760, 1762, 1763, 1765, 1767, 1768, 1770, 1771, 1773, 1774, 1776, 1777, 1779, 1780, 1781, 1783,
+  1784, 1786, 1787, 1789, 1791, 1792, 1794, 1795, 1797, 1799, 1801, 1802, 1804, 1806, 1808, 1809,
+  1811, 1813, 1814, 1816, 1818, 1819, 1821, 1822, 1824, 1826, 1827, 1829, 1831, 1832, 1834, 1835,
+  1837, 1839, 1841, 1842, 1844, 1846, 1848, 1849, 1851, 1853, 1854, 1856, 1858, 1859, 1861, 1862,
+  1864, 1866, 1868, 1869, 1871, 1873, 1875, 1876, 1878, 1880, 1881, 1883, 1885, 1886, 1888, 1889,
+  1891, 1893, 1894, 1896, 1898, 1899, 1901, 1902, 1904, 1906, 1908, 1909, 1911, 1913, 1915, 1916,
+  1918, 1920, 1922, 1924, 1926, 1927, 1929, 1931, 1933, 1935, 1937, 1938, 1940, 1942, 1944, 1945,
+  1947, 1949, 1951, 1953, 1955, 1957, 1959, 1961, 1963, 1965, 1967, 1968, 1970, 1972, 1974, 1975,
+  1977, 1979, 1981, 1983, 1985, 1986, 1988, 1990, 1992, 1994, 1996, 1998, 2000, 2001, 2003, 2005,
+  2007, 2009, 2011, 2013, 2015, 2016, 2018, 2020, 2022, 2024, 2026, 2027, 2029, 2031, 2033, 2034,
+  2036, 2038, 2040, 2042, 2044, 2046, 2048, 2050, 2052, 2054, 2056, 2058, 2060, 2062, 2064, 2066,
+  2068, 2070, 2072, 2074, 2076, 2078, 2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, 2096, 2098,
+  2100, 2102, 2104, 2106, 2109, 2111, 2113, 2115, 2117, 2119, 2121, 2123, 2125, 2127, 2129, 2131,
+  2133, 2135, 2137, 2139, 2141, 2143, 2145, 2147, 2149, 2151, 2153, 2155, 2157, 2159, 2161, 2163,
+  2165, 2167, 2170, 2172, 2175, 2177, 2179, 2182, 2184, 2186, 2188, 2190, 2193, 2195, 2197, 2199,
+  2201, 2203, 2206, 2208, 2210, 2212, 2215, 2217, 2219, 2221, 2224, 2226, 2228, 2230, 2233, 2235,
+  2237, 2239, 2242, 2244, 2247, 2249, 2251, 2254, 2256, 2258, 2261, 2263, 2265, 2267, 2270, 2272,
+  2274, 2276, 2279, 2281, 2283, 2285, 2288, 2290, 2292, 2294, 2297, 2299, 2302, 2304, 2306, 2309,
+  2311, 2314, 2316, 2319, 2321, 2324, 2326, 2329, 2331, 2333, 2336, 2338, 2340, 2342, 2345, 2347,
+  2349, 2352, 2354, 2357, 2359, 2362, 2364, 2367, 2369, 2371, 2374, 2376, 2379, 2381, 2383, 2386,
+  2388, 2390, 2393, 2395, 2398, 2400, 2402, 2405, 2407, 2410, 2412, 2415, 2417, 2420, 2422, 2425,
+  2427, 2430, 2432, 2435, 2438, 2440, 2443, 2445, 2448, 2451, 2453, 2456, 2459, 2461, 2464, 2466,
+  2469, 2472, 2475, 2477, 2480, 2483, 2486, 2488, 2491, 2494, 2496, 2499, 2501, 2504, 2506, 2509,
+  2511, 2514, 2517, 2519, 2522, 2525, 2528, 2530, 2533, 2536, 2538, 2541, 2543, 2546, 2548, 2551,
+  2553, 2556, 2559, 2561, 2564, 2567, 2570, 2572, 2575, 2578, 2581, 2584, 2587, 2589, 2592, 2595,
+  2598, 2601, 2604, 2606, 2609, 2612, 2615, 2617, 2620, 2623, 2626, 2629, 2632, 2634, 2637, 2640,
+  2643, 2646, 2649, 2652, 2655, 2657, 2660, 2663, 2666, 2669, 2672, 2675, 2678, 2680, 2683, 2686,
+  2689, 2692, 2695, 2698, 2701, 2704, 2707, 2710, 2713, 2716, 2719, 2722, 2725, 2727, 2730, 2733,
+  2736, 2739, 2742, 2745, 2749, 2752, 2755, 2758, 2761, 2764, 2767, 2770, 2773, 2776, 2779, 2782,
+  2785, 2788, 2791, 2794, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2823, 2826, 2829, 2832,
+  2835, 2838, 2841, 2844, 2848, 2851, 2854, 2857, 2860, 2863, 2867, 2870, 2873, 2876, 2880, 2883,
+  2886, 2889, 2893, 2896, 2899, 2902, 2906, 2909, 2912, 2915, 2919, 2922, 2925, 2928, 2932, 2935,
+  2938, 2941, 2945, 2948, 2952, 2955, 2958, 2962, 2965, 2968, 2972, 2975, 2979, 2982, 2985, 2989,
+  2992, 2995, 2999, 3002, 3006, 3009, 3012, 3016, 3019, 3023, 3026, 3030, 3033, 3037, 3040, 3044,
+  3047, 3051, 3054, 3058, 3061, 3065, 3068, 3072, 3075, 3079, 3082, 3086, 3089, 3093, 3096, 3100,
+  3103, 3107, 3110, 3114, 3118, 3121, 3125, 3128, 3132, 3136, 3139, 3143, 3146, 3150, 3153, 3157,
+  3160, 3164, 3168, 3171, 3175, 3179, 3183, 3186, 3190, 3194, 3197, 3201, 3205, 3208, 3212, 3215,
+  3219, 3223, 3227, 3231, 3235, 3238, 3242, 3246, 3250, 3254, 3258, 3261, 3265, 3269, 3273, 3276,
+  3280, 3284, 3288, 3292, 3296, 3299, 3303, 3307, 3311, 3315, 3319, 3323, 3327, 3331, 3335, 3339,
+  3343, 3347, 3351, 3354, 3358, 3362, 3366, 3369, 3373, 3377, 3381, 3385, 3389, 3393, 3397, 3401,
+  3405, 3409, 3413, 3417, 3422, 3426, 3430, 3434, 3438, 3442, 3446, 3450, 3455, 3459, 3463, 3467,
+  3471, 3475, 3479, 3483, 3487, 3491, 3495, 3499, 3503, 3507, 3512, 3516, 3520, 3524, 3529, 3533,
+  3537, 3541, 3546, 3550, 3554, 3558, 3563, 3567, 3571, 3575, 3580, 3584, 3589, 3593, 3597, 3602,
+  3606, 3610, 3615, 3619, 3624, 3628, 3632, 3637, 3641, 3645, 3650, 3654, 3658, 3662, 3667, 3671,
+  3675, 3680, 3684, 3689, 3693, 3698, 3702, 3707, 3711, 3716, 3720, 3725, 3729, 3734, 3738, 3743,
+  3747, 3752, 3756, 3761, 3766, 3770, 3775, 3779, 3784, 3789, 3793, 3798, 3802, 3807, 3811, 3816,
+  3820, 3825, 3830, 3834, 3839, 3844, 3849, 3853, 3858, 3863, 3868, 3872, 3877, 3882, 3887, 3891,
+  3896, 3901, 3906, 3910, 3915, 3920, 3925, 3929, 3934, 3939, 3944, 3949, 3954, 3958, 3963, 3968,
+  3973, 3978, 3983, 3988, 3993, 3997, 4002, 4007, 4012, 4017, 4022, 4027, 4032, 4037, 4042, 4047,
+  4052, 4057, 4062, 4067, 4072, 4077, 4082, 4087, 4092, 4097, 4102, 4107, 4113, 4118, 4123, 4128,
+  4133, 4138, 4143, 4148, 4154, 4159, 4164, 4169, 4174, 4179, 4185, 4190, 4195, 4200, 4206, 4211,
+  4216, 4221, 4227, 4232, 4237, 4242, 4248, 4253, 4258, 4263, 4269, 4274, 4280, 4285, 4290, 4296,
+  4301, 4306, 4312, 4317, 4323, 4328, 4333, 4339, 4344, 4350, 4355, 4361, 4366, 4372, 4377, 4383,
+  4388, 4394, 4399, 4405, 4410, 4416, 4421, 4427, 4432, 4438, 4444, 4449, 4455, 4461, 4467, 4472,
+  4478, 4484, 4489, 4495, 4500, 4506, 4511, 4517, 4522, 4528, 4534, 4540, 4546, 4551, 4557, 4563,
+  4569, 4575, 4581, 4586, 4592, 4598, 4604, 4609, 4615, 4621, 4627, 4633, 4639, 4644, 4650, 4656,
+  4662, 4668, 4674, 4680, 4686, 4692, 4698, 4704, 4710, 4716, 4722, 4728, 4734, 4740, 4746, 4752,
+  4758, 4764, 4771, 4777, 4783, 4789, 4796, 4802, 4808, 4814, 4820, 4826, 4832, 4838, 4844, 4850,
+  4856, 4862, 4869, 4875, 4882, 4888, 4894, 4901, 4907, 4913, 4920, 4926, 4933, 4939, 4945, 4952,
+  4958, 4964, 4971, 4977, 4983, 4989, 4996, 5002, 5008, 5015, 5021, 5028, 5034, 5041, 5047, 5054,
+  5060, 5067, 5073, 5080, 5087, 5093, 5100, 5106, 5113, 5120, 5126, 5133, 5140, 5146, 5153, 5159,
+  5166, 5173, 5180, 5186, 5193, 5200, 5207, 5213, 5220, 5227, 5234, 5240, 5247, 5254, 5261, 5267,
+  5274, 5281, 5288, 5295, 5302, 5309, 5316, 5323, 5330, 5337, 5344, 5351, 5358, 5365, 5372, 5379,
+  5386, 5393, 5400, 5407, 5414, 5421, 5428, 5435, 5442, 5449, 5456, 5463, 5471, 5478, 5485, 5492,
+  5499, 5506, 5514, 5521, 5528, 5535, 5543, 5550, 5557, 5564, 5572, 5579, 5587, 5594, 5601, 5609,
+  5616, 5623, 5631, 5638, 5646, 5653, 5660, 5668, 5675, 5683, 5690, 5698, 5705, 5713, 5720, 5728,
+  5735, 5743, 5751, 5758, 5766, 5774, 5782, 5789, 5797, 5805, 5812, 5820, 5828, 5835, 5843, 5850,
+  5858, 5866, 5874, 5881, 5889, 5897, 5905, 5912, 5920, 5928, 5936, 5944, 5952, 5959, 5967, 5975,
+  5983, 5991, 5999, 6007, 6015, 6023, 6031, 6039, 6047, 6055, 6063, 6071, 6079, 6087, 6095, 6103,
+  6111, 6119, 6128, 6136, 6144, 6152, 6161, 6169, 6177, 6185, 6194, 6202, 6210, 6218, 6227, 6235,
+  6243, 6251, 6260, 6268, 6277, 6285, 6293, 6302, 6310, 6319, 6327, 6336, 6344, 6353, 6361, 6370,
+  6378, 6387, 6395, 6404, 6412, 6421, 6429, 6438, 6446, 6455, 6464, 6472, 6481, 6490, 6499, 6507,
+  6516, 6525, 6534, 6543, 6552, 6560, 6569, 6578, 6587, 6596, 6605, 6613, 6622, 6631, 6640, 6648,
+  6657, 6666, 6675, 6684, 6694, 6703, 6712, 6721, 6730, 6739, 6748, 6757, 6767, 6776, 6785, 6794,
+  6803, 6812, 6822, 6831, 6840, 6849, 6859, 6868, 6877, 6886, 6896, 6905, 6914, 6923, 6933, 6942,
+  6951, 6961, 6970, 6980, 6989, 6999, 7008, 7018, 7027, 7037, 7046, 7056, 7065, 7075, 7084, 7094,
+  7103, 7113, 7123, 7132, 7142, 7152, 7162, 7171, 7181, 7191, 7201, 7210, 7220, 7230, 7240, 7249,
+  7259, 7269, 7279, 7289, 7299, 7309, 7319, 7329, 7339, 7349, 7359, 7369, 7379, 7389, 7399, 7409,
+  7419, 7429, 7440, 7450, 7460, 7470, 7481, 7491, 7501, 7511, 7522, 7532, 7543, 7553, 7563, 7574,
+  7584, 7594, 7605, 7615, 7626, 7636, 7646, 7657, 7667, 7678, 7688, 7699, 7709, 7720, 7730, 7741,
+  7751, 7762, 7772, 7783, 7794, 7804, 7815, 7825, 7836, 7847, 7858, 7869, 7880, 7890, 7901, 7912,
+  7923, 7934, 7945, 7956, 7967, 7977, 7988, 7999, 8010, 8021, 8032, 8043, 8055, 8066, 8077, 8088,
+  8099, 8110, 8122, 8133, 8144, 8155, 8167, 8178, 8189, 8200, 8212, 8223, 8234, 8245, 8257, 8268,
+  8279, 8291, 8302, 8314, 8326, 8337, 8349, 8360, 8372, 8384, 8395, 8407, 8418, 8430, 8441, 8453,
+  8464, 8476, 8488, 8500, 8512, 8523, 8535, 8547, 8559, 8571, 8583, 8595, 8607, 8618, 8630, 8642,
+  8654, 8666, 8678, 8690, 8702, 8714, 8726, 8738, 8750, 8762, 8775, 8787, 8799, 8811, 8824, 8836,
+  8848, 8860, 8873, 8885, 8898, 8910, 8922, 8935, 8947, 8960, 8972, 8985, 8997, 9010, 9022, 9035,
+  9047, 9060, 9072, 9085, 9098, 9110, 9123, 9135, 9148, 9161, 9174, 9187, 9200, 9212, 9225, 9238,
+  9251, 9264, 9277, 9290, 9303, 9316, 9329, 9342, 9355, 9368, 9381, 9394, 9408, 9421, 9434, 9447,
+  9460, 9473, 9487, 9500, 9513, 9526, 9540, 9553, 9566, 9580, 9593, 9607, 9620, 9634, 9647, 9661,
+  9674, 9688, 9701, 9715, 9728, 9742, 9755, 9769, 9782, 9796, 9810, 9824, 9838, 9851, 9865, 9879,
+  9893, 9907, 9921, 9935, 9949, 9963, 9977, 9991, 10005, 10019, 10033, 10047, 10061, 10075, 10089, 10103,
+  10117, 10131, 10146, 10160, 10175, 10189, 10203, 10218, 10232, 10247, 10261, 10276, 10290, 10305, 10319, 10334,
+  10348, 10363, 10377, 10392, 10407, 10421, 10436, 10450, 10465, 10480, 10495, 10509, 10524, 10539, 10554, 10568,
+  10583, 10598, 10613, 10628, 10643, 10658, 10673, 10688, 10703, 10718, 10734, 10749, 10764, 10779, 10795, 10810,
+  10825, 10840, 10856, 10871, 10887, 10902, 10917, 10933, 10948, 10964, 10979, 10995, 11010, 11026, 11041, 11057,
+  11072, 11088, 11104, 11120, 11136, 11151, 11167, 11183, 11199, 11215, 11231, 11247, 11263, 11278, 11294, 11310,
+  11326, 11342, 11358, 11374, 11391, 11407, 11423, 11439, 11455, 11471, 11488, 11504, 11521, 11537, 11553, 11570,
+  11586, 11603, 11619, 11636, 11652, 11669, 11685, 11702, 11718, 11735, 11752, 11768, 11785, 11802, 11819, 11835,
+  11852, 11869, 11886, 11903, 11920, 11937, 11954, 11971, 11988, 12005, 12022, 12039, 12057, 12074, 12091, 12108,
+  12125, 12142, 12160, 12177, 12195, 12212, 12229, 12247, 12264, 12282, 12299, 12317, 12335, 12352, 12370, 12387,
+  12405, 12423, 12441, 12458, 12476, 12494, 12512, 12529, 12547, 12565, 12583, 12601, 12619, 12637, 12655, 12673,
+  12691, 12709, 12728, 12746, 12764, 12782, 12801, 12819, 12837, 12855, 12874, 12892, 12911, 12929, 12947, 12966,
+  12984, 13003, 13022, 13040, 13059, 13078, 13097, 13115, 13134, 13153, 13172, 13191, 13210, 13228, 13247, 13266,
+  13285, 13304, 13323, 13342, 13362, 13381, 13400, 13419, 13438, 13457, 13477, 13496, 13516, 13535, 13554, 13574,
+  13593, 13613, 13632, 13652, 13672, 13691, 13711, 13730, 13750, 13770, 13790, 13810, 13830, 13849, 13869, 13889,
+  13909, 13929, 13949, 13969, 13990, 14010, 14030, 14050, 14070, 14090, 14111, 14131, 14151, 14171, 14192, 14212,
+  14232, 14253, 14273, 14294, 14315, 14335, 14356, 14376, 14397, 14418, 14439, 14460, 14481, 14501, 14522, 14543,
+  14564, 14585, 14606, 14627, 14648, 14669, 14690, 14711, 14732, 14753, 14775, 14796, 14818, 14839, 14860, 14882,
+  14903, 14925, 14946, 14968, 14990, 15011, 15033, 15054, 15076, 15098, 15120, 15142, 15164, 15185, 15207, 15229,
+  15251, 15273, 15295, 15317, 15340, 15362, 15384, 15406, 15428, 15450, 15473, 15495, 15518, 15540, 15562, 15585,
+  15607, 15630, 15653, 15675, 15698, 15721, 15744, 15766, 15789, 15812, 15835, 15858, 15881, 15903, 15926, 15949,
+  15972, 15995, 16019, 16042, 16065, 16088, 16112, 16135, 16158, 16182, 16205, 16229, 16253, 16276, 16300, 16323,
+  16347, 16371, 16395, 16418, 16442, 16466, 16490, 16513, 16537, 16561, 16585, 16609, 16634, 16658, 16682, 16706,
+  16730, 16754, 16779, 16803, 16828, 16852, 16876, 16901, 16925, 16950, 16975, 16999, 17024, 17049, 17074, 17098,
+  17123, 17148, 17173, 17198, 17223, 17248, 17273, 17298, 17323, 17348, 17374, 17399, 17424, 17449, 17475, 17500,
+  17525, 17551, 17576, 17602, 17628, 17653, 17679, 17704, 17730, 17756, 17782, 17808, 17834, 17860, 17886, 17912,
+  17938, 17964, 17991, 18017, 18043, 18069, 18096, 18122, 18148, 18175, 18201, 18228, 18254, 18281, 18307, 18334,
+  18360, 18387, 18414, 18441, 18468, 18494, 18521, 18548, 18575, 18602, 18630, 18657, 18684, 18711, 18739, 18766,
+  18793, 18821, 18848, 18876, 18904, 18931, 18959, 18986, 19014, 19042, 19070, 19097, 19125, 19153, 19181, 19208,
+  19236, 19264, 19293, 19321, 19349, 19377, 19406, 19434, 19462, 19491, 19519, 19548, 19577, 19605, 19634, 19662,
+  19691, 19720, 19749, 19778, 19807, 19835, 19864, 19893, 19922, 19951, 19981, 20010, 20040, 20069, 20098, 20128,
+  20157, 20187, 20216, 20246, 20276, 20305, 20335, 20364, 20394, 20424, 20454, 20484, 20514, 20544, 20574, 20604,
+  20634, 20664, 20695, 20725, 20756, 20786, 20816, 20847, 20877, 20908, 20939, 20969, 21000, 21031, 21062, 21092,
+  21123, 21154, 21185, 21216, 21247, 21278, 21309, 21340, 21371, 21403, 21434, 21466, 21497, 21529, 21560, 21592,
+  21623, 21655, 21687, 21719, 21751, 21782, 21814, 21846, 21878, 21910, 21943, 21975, 22007, 22039, 22072, 22104,
+  22136, 22169, 22202, 22234, 22267, 22300, 22333, 22365, 22398, 22431, 22464, 22497, 22530, 22563, 22596, 22629,
+  22662, 22696, 22729, 22763, 22796, 22830, 22863, 22897, 22930, 22964, 22998, 23032, 23066, 23099, 23133, 23167,
+  23201, 23235, 23270, 23304, 23338, 23372, 23407, 23441, 23475, 23510, 23545, 23579, 23614, 23649, 23684, 23718,
+  23753, 23788, 23823, 23858, 23894, 23929, 23964, 23999, 24034, 24070, 24105, 24141, 24176, 24212, 24247, 24283,
+  24318, 24354, 24390, 24426, 24462, 24498, 24534, 24570, 24606, 24643, 24679, 24716, 24752, 24789, 24825, 24862,
+  24898, 24935, 24972, 25009, 25046, 25082, 25119, 25156, 25193, 25230, 25268, 25305, 25342, 25379, 25417, 25454,
+  25491, 25529, 25567, 25605, 25643, 25680, 25718, 25756, 25794, 25832, 25871, 25909, 25947, 25985, 26024, 26062,
+  26100, 26139, 26178, 26216, 26255, 26294, 26333, 26371, 26410, 26449, 26488, 26527, 26567, 26606, 26645, 26684,
+  26723, 26763, 26802, 26842, 26882, 26921, 26961, 27000, 27040, 27080, 27121, 27161, 27201, 27241, 27282, 27322,
+  27362, 27403, 27443, 27484, 27525, 27565, 27606, 27646, 27687, 27728, 27769, 27810, 27852, 27893, 27934, 27975,
+  28016, 28058, 28099, 28141, 28183, 28224, 28266, 28307, 28349, 28391, 28433, 28475, 28518, 28560, 28602, 28644,
+  28686, 28729, 28772, 28814, 28857, 28900, 28943, 28985, 29028, 29071, 29114, 29157, 29201, 29244, 29287, 29330,
+  29373, 29417, 29461, 29504, 29548, 29592, 29636, 29679, 29723, 29767, 29812, 29856, 29900, 29944, 29989, 30033,
+  30077, 30122, 30167, 30211, 30256, 30301, 30346, 30390, 30435, 30480, 30526, 30571, 30617, 30662, 30707, 30753,
+  30798, 30844, 30890, 30936, 30982, 31027, 31073, 31119, 31165, 31212, 31258, 31305, 31351, 31398, 31444, 31491,
+  31537, 31584, 31631, 31678, 31725, 31772, 31819, 31866, 31913, 31961, 32008, 32056, 32104, 32151, 32199, 32246,
+  32294, 32342, 32390, 32438, 32487, 32535, 32583, 32631, 32679, 32766, 32777, 32825, 32874, 32923, 32972, 33020,
+  33069, 33118, 33168, 33217, 33267, 33316, 33365, 33415, 33464, 33514, 33564, 33614, 33664, 33714, 33764, 33814,
+  33864, 33915, 33965, 34016, 34067, 34117, 34168, 34218, 34269, 34320, 34371, 34422, 34474, 34525, 34576, 34627,
+  34678, 34730, 34782, 34834, 34886, 34937, 34989, 35041, 35093, 35146, 35198, 35251, 35303, 35356, 35408, 35461,
+  35513, 35566, 35619, 35672, 35725, 35778, 35831, 35884, 35937, 35991, 36045, 36098, 36152, 36206, 36260, 36313,
+  36367, 36422, 36476, 36531, 36585, 36640, 36694, 36749, 36803, 36858, 36913, 36968, 37023, 37078, 37133, 37188,
+  37243, 37299, 37355, 37410, 37466, 37522, 37578, 37633, 37689, 37746, 37802, 37859, 37915, 37972, 38028, 38085,
+  38141, 38198, 38255, 38312, 38369, 38426, 38483, 38540, 38597, 38655, 38713, 38771, 38829, 38886, 38944, 39002
+};
+
+static inline ushort sony_arw6_llvc3_lut_value(int code)
+{
+  if (code < 0)
+    code = 0;
+  if (code > 4095)
+    code = 4095;
+  return sony_arw6_llvc3_curve[code];
+}
+
+static size_t sony_arw6_checked_plane_samples(int rows, int cols)
+{
+  sony_arw6_require(rows >= 0 && cols >= 0);
+  const uint64_t r = uint64_t(rows);
+  const uint64_t c = uint64_t(cols);
+  sony_arw6_require(c == 0 || r <= uint64_t(~size_t(0)) / c);
+  const uint64_t samples = r * c;
+  sony_arw6_require(samples <= uint64_t(SONY_ARW6_MAX_PLANE_SAMPLES));
+  return size_t(samples);
+}
+
+struct SonyArw6Plane
+{
+  int rows;
+  int cols;
+  std::vector<int32_t> data;
+
+  SonyArw6Plane() : rows(0), cols(0) {}
+  SonyArw6Plane(int r, int c)
+      : rows(r), cols(c), data(sony_arw6_checked_plane_samples(r, c))
+  {
+  }
+
+  int32_t &at(int r, int c) { return data[size_t(r) * size_t(cols) + c]; }
+  const int32_t &at(int r, int c) const
+  {
+    return data[size_t(r) * size_t(cols) + c];
+  }
+  int32_t *row(int r) { return &data[size_t(r) * size_t(cols)]; }
+  const int32_t *row(int r) const { return &data[size_t(r) * size_t(cols)]; }
+};
+
+struct SonyArw6DirectoryEntry
+{
+  int group;
+  int index;
+  uint32_t start;
+  uint32_t length;
+};
+
+struct SonyArw6StreamInfo
+{
+  int index;
+  uint32_t offset;
+  uint32_t length;
+  int tile_x;
+  int tile_y;
+  int tile_w;
+  int tile_h;
+  int coded_width;
+  int coded_half_height;
+  int logical_height;
+};
+
+struct SonyArw6PacketRecord
+{
+  uint32_t byte_length;
+  uchar selectors[3];
+  uint32_t payload_offset;
+};
+
+struct SonyArw6Packet
+{
+  int type;
+  int block_count;
+  uint32_t control_bytes;
+  uint32_t total_bytes;
+  const uchar *data;
+  uint32_t length;
+  std::vector<SonyArw6PacketRecord> records;
+};
+
+static uint32_t sony_arw6_stream_payload_length(const uchar *stream,
+                                                uint32_t stream_size)
+{
+  sony_arw6_require(stream_size >= 0x80);
+  uint32_t payload = 0;
+  const int offs[5] = {0, 3, 6, 9, 12};
+  for (int g = 0; g < 5; g++)
+    payload +=
+        ((sony_arw6_be32(stream + 0x10 + offs[g]) >> 4) & 0x0ffffff0);
+  sony_arw6_require(payload <= stream_size - 0x80);
+  return 0x80 + payload;
+}
+
+static bool sony_arw6_parse_stream_header(const uchar *stream,
+                                          uint32_t stream_size,
+                                          SonyArw6StreamInfo &info)
+{
+  if (stream_size < 0x80 ||
+      (memcmp(stream, "A000", 4) && memcmp(stream, "0000", 4)))
+    return false;
+  const uint16_t word_c = sony_arw6_be16(stream + 0x0c);
+  const uint16_t word_e = sony_arw6_be16(stream + 0x0e);
+  const int decoded_bits = (word_c >> 4) & 0x3f;
+  const int components = word_e >> 13;
+  const int mode = (word_e >> 10) & 0x03;
+  if (decoded_bits != 16 || components != 3 || mode != 3)
+    return false;
+  info.coded_width = sony_arw6_be16(stream + 8);
+  info.coded_half_height = sony_arw6_be16(stream + 0x0a);
+  info.logical_height = info.coded_half_height * 2;
+  if (info.coded_width <= 0 || info.coded_half_height <= 0 ||
+      (info.coded_width & 15))
+    return false;
+  return true;
+}
+
+static std::vector<SonyArw6StreamInfo>
+sony_arw6_find_streams(const std::vector<uchar> &strip, int full_width,
+                       int full_height)
+{
+  std::vector<SonyArw6StreamInfo> streams;
+  if (full_width <= 0 || full_height <= 0)
+    return streams;
+  const uint32_t strip_size = uint32_t(strip.size());
+  const uchar *base = strip_size ? &strip[0] : 0;
+  if (!base || strip_size < SONY_ARW6_STREAM_OFFSET + 0x80)
+    return streams;
+
+  const uint32_t count = sony_arw6_le32(base);
+  if (count >= 1 && count <= 16)
+  {
+    for (uint32_t index = 0; index < count; index++)
+    {
+      const uint32_t entry = 0x08 + index * 0x18;
+      if (entry + 0x18 > strip_size)
+      {
+        streams.clear();
+        break;
+      }
+      const uint32_t table_offset = sony_arw6_le32(base + entry);
+      const int tile_x = int(sony_arw6_le32(base + entry + 0x08));
+      const int tile_y = int(sony_arw6_le32(base + entry + 0x0c));
+      const int entry_tile_w = int(sony_arw6_le32(base + entry + 0x10));
+      const int entry_tile_h = int(sony_arw6_le32(base + entry + 0x14));
+      const uint32_t start = table_offset ? table_offset : SONY_ARW6_STREAM_OFFSET;
+      if (start > strip_size - 0x80)
+      {
+        streams.clear();
+        break;
+      }
+      const uint32_t search_end =
+          std::min(strip_size - 0x80,
+                   start > UINT32_MAX - uint32_t(0x1000)
+                       ? UINT32_MAX
+                       : start + uint32_t(0x1000));
+      bool found = false;
+      SonyArw6StreamInfo info;
+      for (uint32_t candidate = start; candidate <= search_end;
+           candidate += 0x10)
+      {
+        if (!sony_arw6_parse_stream_header(base + candidate,
+                                           strip_size - candidate, info))
+          continue;
+        uint32_t length =
+            sony_arw6_stream_payload_length(base + candidate,
+                                            strip_size - candidate);
+        if (length <= 0x80 || candidate + length > strip_size)
+          continue;
+        info.index = int(index);
+        info.offset = candidate;
+        info.length = length;
+        info.tile_x = tile_x;
+        info.tile_y = tile_y;
+        info.tile_w = entry_tile_w ? entry_tile_w : info.coded_width;
+        info.tile_h = entry_tile_h ? entry_tile_h : info.logical_height;
+        if (info.tile_x < 0 || info.tile_y < 0 ||
+            info.tile_w != info.coded_width ||
+            info.tile_h != info.logical_height ||
+            info.tile_x > full_width - info.tile_w ||
+            info.tile_y > full_height - info.tile_h)
+          continue;
+        streams.push_back(info);
+        found = true;
+        break;
+      }
+      if (!found)
+      {
+        streams.clear();
+        break;
+      }
+    }
+    if (streams.size() == count)
+      return streams;
+  }
+
+  SonyArw6StreamInfo info;
+  if (sony_arw6_parse_stream_header(base + SONY_ARW6_STREAM_OFFSET,
+                                    strip_size - SONY_ARW6_STREAM_OFFSET,
+                                    info))
+  {
+    info.index = 0;
+    info.offset = SONY_ARW6_STREAM_OFFSET;
+    info.length =
+        sony_arw6_stream_payload_length(base + info.offset,
+                                        strip_size - info.offset);
+    info.tile_x = 0;
+    info.tile_y = 0;
+    info.tile_w = info.coded_width;
+    info.tile_h = info.logical_height;
+    if (info.coded_width == full_width && info.logical_height == full_height)
+      streams.push_back(info);
+  }
+  return streams;
+}
+
+class SonyArw6HeaderBits
+{
+  const uchar *data_;
+  uint32_t size_;
+  uint32_t bitpos_;
+
+public:
+  SonyArw6HeaderBits(const uchar *data, uint32_t size)
+      : data_(data), size_(size), bitpos_(0)
+  {
+  }
+
+  uint32_t read(int nbits)
+  {
+    sony_arw6_require(nbits >= 0 && nbits <= 32);
+    sony_arw6_require(uint64_t(bitpos_) + uint32_t(nbits) <=
+                      uint64_t(size_) * 8U);
+    uint32_t out = 0;
+    for (int i = 0; i < nbits; i++)
+    {
+      const uchar byte = data_[bitpos_ >> 3];
+      const uint32_t bit = (byte >> (7 - (bitpos_ & 7))) & 1;
+      out = (out << 1) | bit;
+      bitpos_++;
+    }
+    return out;
+  }
+};
+
+class SonyArw6NativeBits
+{
+  const uchar *data_;
+  uint32_t size_;
+  int64_t ptr_;
+  uint64_t cur_;
+  int bit_;
+  int words_left_;
+
+public:
+  int status;
+
+  SonyArw6NativeBits(const uchar *packet, uint32_t packet_len,
+                     uint32_t payload_offset, uint32_t byte_length)
+      : data_(packet), size_(packet_len), ptr_(int64_t(payload_offset) - 8),
+        cur_(0), bit_(0),
+        words_left_(((((int)byte_length + 7) / 8) + 1) & ~1), status(0)
+  {
+  }
+
+  void load_next_word()
+  {
+    words_left_--;
+    if (words_left_ < 0)
+    {
+      status = 2;
+      return;
+    }
+    ptr_ += 8;
+    uint64_t x = 0;
+    for (int i = 0; i < 8; i++)
+    {
+      x <<= 8;
+      const int64_t pos = ptr_ + i;
+      if (pos >= 0 && pos < int64_t(size_))
+        x |= data_[pos];
+    }
+    cur_ = x;
+    bit_ = 64;
+  }
+
+  uint32_t read_bits(int nbits)
+  {
+    sony_arw6_require(nbits >= 0 && nbits <= 32);
+    uint32_t out = 0;
+    int remaining = nbits;
+    while (remaining > 0)
+    {
+      if (bit_ <= 0)
+      {
+        load_next_word();
+        if (status)
+          return out << remaining;
+      }
+      const int take = std::min(remaining, bit_);
+      bit_ -= take;
+      out = (out << take) |
+            uint32_t((cur_ >> bit_) & ((uint64_t(1) << take) - 1));
+      remaining -= take;
+    }
+    return out;
+  }
+
+  int read_unary_zeros_plus_one()
+  {
+    int zeros = 0;
+    while (!status)
+    {
+      const uint32_t bit = read_bits(1);
+      if (status)
+        break;
+      if (bit)
+        return zeros + 1;
+      zeros++;
+    }
+    return zeros + 1;
+  }
+};
+
+static int sony_arw6_update_width(SonyArw6NativeBits &br, int wstate)
+{
+  if (br.read_bits(1) == 0 || br.status)
+    return wstate;
+  if (br.read_bits(1) == 0 || br.status)
+    return wstate + br.read_unary_zeros_plus_one();
+
+  for (int zeros = 0; zeros < std::max(0, wstate - 1); zeros++)
+  {
+    if (br.read_bits(1))
+      return wstate - (zeros + 1);
+  }
+  return 0;
+}
+
+static int sony_arw6_read_zero_run(SonyArw6NativeBits &br, int remaining)
+{
+  if (remaining <= 1)
+    return remaining;
+  int max_prefix = 0;
+  for (int x = remaining - 1; x; x >>= 1)
+    max_prefix++;
+  int zeros = 0;
+  while (zeros < max_prefix)
+  {
+    if (br.read_bits(1))
+      break;
+    if (br.status)
+      return remaining;
+    zeros++;
+  }
+  if (zeros >= max_prefix)
+    return remaining;
+  const int base = 1 << zeros;
+  if (base >= remaining)
+    return remaining;
+  const int extra = zeros ? int(br.read_bits(zeros)) : 0;
+  return std::min(base + extra, remaining);
+}
+
+static void sony_arw6_decode_coeff_group(SonyArw6NativeBits &br, int nbits,
+                                         int shift, int32_t vals[4])
+{
+  for (int i = 0; i < 4; i++)
+  {
+    uint32_t x = nbits > 0 ? br.read_bits(nbits) : 0;
+    int32_t v = int32_t(x);
+    if (shift > 0 && x > 0)
+      v = int32_t(((uint64_t(2) * x + 1) << (shift - 1)) - (x & 1));
+    vals[i] = v;
+  }
+}
+
+static void sony_arw6_apply_signs(SonyArw6NativeBits &br, int32_t vals[4])
+{
+  for (int i = 0; i < 4; i++)
+    if (vals[i] > 0)
+    {
+      const uint32_t bit = br.read_bits(1);
+      vals[i] = vals[i] - 2 * vals[i] * int32_t(bit);
+    }
+}
+
+static void sony_arw6_decode_component(SonyArw6NativeBits &br, int groups,
+                                       int shift, int32_t *dst, int row_width)
+{
+  int width_state = sony_arw6_update_width(br, 0);
+  int gi = 0;
+  int out = 0;
+  while (gi < groups)
+  {
+    if (br.status || width_state > 0x13)
+    {
+      br.status = br.status ? br.status : 1;
+      while (out < row_width)
+        dst[out++] = 0;
+      return;
+    }
+    if (width_state == 0)
+    {
+      const int run = sony_arw6_read_zero_run(br, groups - gi);
+      for (int r = 0; r < run; r++)
+        for (int k = 0; k < 4 && out < row_width; k++)
+          dst[out++] = 0;
+      gi += run;
+      if (gi >= groups)
+        break;
+      width_state = br.read_unary_zeros_plus_one();
+      continue;
+    }
+
+    int32_t vals[4];
+    sony_arw6_decode_coeff_group(br, width_state, shift, vals);
+    const int next_width =
+        gi + 1 < groups ? sony_arw6_update_width(br, width_state) : width_state;
+    sony_arw6_apply_signs(br, vals);
+    for (int k = 0; k < 4 && out < row_width; k++)
+      dst[out++] = vals[k];
+    width_state = next_width;
+    gi++;
+  }
+  while (out < row_width)
+    dst[out++] = 0;
+}
+
+static int sony_arw6_row_multiplier(int group)
+{
+  if (group == 4)
+    return 8;
+  if (group == 0)
+    return 1;
+  return 1 << (group - 1);
+}
+
+static int sony_arw6_infer_packet_width(int group, int packet_type,
+                                        int mosaic_width)
+{
+  sony_arw6_require(mosaic_width > 0 && (mosaic_width & 15) == 0);
+  if (packet_type == 1)
+    return group == 4 ? mosaic_width / 2 : mosaic_width / 16;
+  if (packet_type == 3 && group >= 1 && group <= 3)
+    return mosaic_width / (1 << (5 - group));
+  throw LIBRAW_EXCEPTION_IO_CORRUPT;
+}
+
+static int sony_arw6_expected_packet_rows(int group, int coded_height)
+{
+  sony_arw6_require(group >= 0 && group <= 4);
+  sony_arw6_require(coded_height > 0 && coded_height <= 0x7fff);
+  const int padded_height = sony_arw6_align_up(coded_height, 16);
+  return (padded_height / 16 + 1) * sony_arw6_row_multiplier(group);
+}
+
+static std::vector<SonyArw6DirectoryEntry>
+sony_arw6_parse_directory(const uchar *stream, uint32_t stream_size)
+{
+  sony_arw6_require(stream_size >= 0x80);
+  std::vector<SonyArw6DirectoryEntry> entries;
+  uint32_t group_lengths[5];
+  const int offs[5] = {0, 3, 6, 9, 12};
+  for (int g = 0; g < 5; g++)
+    group_lengths[g] =
+        ((sony_arw6_be32(stream + 0x10 + offs[g]) >> 4) & 0x0ffffff0);
+
+  uint32_t pos = 0x30;
+  uint32_t base = 0;
+  for (int group = 0; group < 5; group++)
+  {
+    sony_arw6_require(pos + 0x10 <= stream_size);
+    const int n_entries = stream[pos] & 0x0f;
+    sony_arw6_require(n_entries >= 0 && n_entries <= 9);
+    uint32_t values[9] = {0};
+    for (int i = 0; i < 5; i++)
+      values[i] = (sony_arw6_be32(stream + pos + offs[i]) & 0x00ffffff) << 4;
+    uint32_t consumed = 0x10;
+    if (n_entries >= 5)
+    {
+      sony_arw6_require(pos + 0x20 <= stream_size);
+      for (int i = 0; i < 4; i++)
+        values[5 + i] =
+            (sony_arw6_be32(stream + pos + 0x10 + offs[i]) & 0x00ffffff)
+            << 4;
+      consumed = 0x20;
+    }
+
+    uint32_t local = 0;
+    for (int index = 0; index < n_entries; index++)
+    {
+      SonyArw6DirectoryEntry e;
+      e.group = group;
+      e.index = index;
+      sony_arw6_require(base <= UINT32_MAX - local &&
+                        0x80 <= UINT32_MAX - base - local);
+      e.start = 0x80 + base + local;
+      e.length = values[index];
+      sony_arw6_require(e.start <= stream_size &&
+                        e.length <= stream_size - e.start);
+      entries.push_back(e);
+      sony_arw6_require(local <= UINT32_MAX - e.length);
+      local += e.length;
+    }
+    sony_arw6_require(local <= group_lengths[group]);
+    sony_arw6_require(base <= UINT32_MAX - group_lengths[group]);
+    base += group_lengths[group];
+    pos += consumed;
+  }
+  return entries;
+}
+
+static SonyArw6DirectoryEntry
+sony_arw6_find_entry(const std::vector<SonyArw6DirectoryEntry> &entries,
+                     int group, int index)
+{
+  for (size_t i = 0; i < entries.size(); i++)
+    if (entries[i].group == group && entries[i].index == index)
+      return entries[i];
+  throw LIBRAW_EXCEPTION_IO_CORRUPT;
+}
+
+static SonyArw6Packet sony_arw6_parse_packet(const uchar *data, uint32_t length)
+{
+  sony_arw6_require(length >= 16);
+  SonyArw6HeaderBits br(data, length);
+  const uint32_t control_count = br.read(16);
+  const uint32_t extra_count = br.read(24);
+  const uint32_t tag4 = br.read(4);
+  const uint32_t reserved4 = br.read(4);
+  const uint32_t type2 = br.read(2);
+  const uint32_t control_words = br.read(6);
+  const uint32_t block_count = br.read(16);
+  const uint32_t width_marker = br.read(8);
+  const uint32_t reserved8 = br.read(8);
+  for (int i = 0; i < 5; i++)
+    sony_arw6_require(br.read(8) == 0);
+
+  sony_arw6_require(tag4 == 4 && reserved4 == 0 && control_words == 0);
+  sony_arw6_require(type2 == 1 || type2 == 3);
+  sony_arw6_require(block_count > 0 && block_count <= 30000);
+  sony_arw6_require(width_marker == 0x10 && reserved8 == 0);
+
+  SonyArw6Packet packet;
+  packet.type = int(type2);
+  packet.block_count = int(block_count);
+  const uint64_t control_bytes = (uint64_t(control_count) + 1U) << 4;
+  const uint64_t total_bytes =
+      (uint64_t(control_count) + 1U + extra_count) << 4;
+  sony_arw6_require(control_bytes <= UINT32_MAX &&
+                    total_bytes <= UINT32_MAX);
+  packet.control_bytes = uint32_t(control_bytes);
+  packet.total_bytes = uint32_t(total_bytes);
+  packet.data = data;
+  packet.length = length;
+  sony_arw6_require(packet.total_bytes == length);
+  sony_arw6_require(packet.control_bytes <= length);
+
+  uint32_t cursor = packet.control_bytes;
+  packet.records.reserve(block_count);
+  for (uint32_t i = 0; i < block_count; i++)
+  {
+    SonyArw6PacketRecord rec;
+    rec.byte_length = br.read(16);
+    memset(rec.selectors, 0, sizeof(rec.selectors));
+    for (uint32_t j = 0; j < type2; j++)
+      rec.selectors[j] = uchar(br.read(4));
+    rec.payload_offset = cursor;
+    sony_arw6_require(rec.byte_length <= length &&
+                      cursor <= length - rec.byte_length);
+    cursor += rec.byte_length;
+    packet.records.push_back(rec);
+  }
+  sony_arw6_require(cursor <= packet.total_bytes);
+  return packet;
+}
+
+static std::vector<SonyArw6Plane>
+sony_arw6_decode_packet_arrays(const uchar *stream, uint32_t stream_size,
+                               const std::vector<SonyArw6DirectoryEntry> &dir,
+                               int mosaic_width, int coded_height, int group,
+                               int index)
+{
+  const SonyArw6DirectoryEntry e = sony_arw6_find_entry(dir, group, index);
+  const SonyArw6Packet p = sony_arw6_parse_packet(stream + e.start, e.length);
+  const int components = p.type == 1 ? 1 : 3;
+  const int row_width = sony_arw6_infer_packet_width(group, p.type, mosaic_width);
+  const int row_multiplier = sony_arw6_row_multiplier(group);
+  const int rows = p.block_count * row_multiplier;
+  const int expected_rows = sony_arw6_expected_packet_rows(group, coded_height);
+  const int groups_per_row = (row_width + 3) / 4;
+  sony_arw6_require(row_width > 0 && groups_per_row > 0 && rows > 0);
+  if (rows != expected_rows)
+    sony_arw6_require((coded_height & 15) &&
+                      expected_rows - rows == row_multiplier);
+  sony_arw6_require(size_t(p.block_count) <=
+                    (stream_size / 16U + 1U)); /* weak corruption guard */
+
+  std::vector<SonyArw6Plane> planes;
+  planes.reserve(components);
+  for (int c = 0; c < components; c++)
+    planes.push_back(SonyArw6Plane(expected_rows, row_width));
+
+  for (int ri = 0; ri < p.block_count; ri++)
+  {
+    const SonyArw6PacketRecord &rec = p.records[ri];
+    SonyArw6NativeBits bits(p.data, p.length, rec.payload_offset,
+                            rec.byte_length);
+    for (int ci = 0; ci < components; ci++)
+    {
+      const int shift = ci < p.type ? rec.selectors[ci] : 0;
+      for (int rm = 0; rm < row_multiplier; rm++)
+      {
+        int32_t *dst = planes[ci].row(ri * row_multiplier + rm);
+        if (rec.byte_length <= 0)
+          memset(dst, 0, sizeof(int32_t) * size_t(row_width));
+        else
+          sony_arw6_decode_component(bits, groups_per_row, shift, dst, row_width);
+      }
+    }
+  }
+  return planes;
+}
+
+static SonyArw6Plane sony_arw6_integrate_type1(const SonyArw6Plane &coeffs,
+                                               int rows, int dc_offset)
+{
+  sony_arw6_require(rows > 0 && rows <= coeffs.rows);
+  SonyArw6Plane out(rows, coeffs.cols);
+  for (int y = 0; y < rows; y++)
+  {
+    int32_t acc = sony_arw6_sign16(coeffs.at(y, 0)) * 2;
+    out.at(y, 0) = acc / 2 + dc_offset;
+    for (int x = 1; x < coeffs.cols; x++)
+    {
+      acc += sony_arw6_sign16(coeffs.at(y, x)) * 2;
+      out.at(y, x) = acc / 2 + dc_offset;
+    }
+  }
+  return out;
+}
+
+static SonyArw6Plane sony_arw6_head_rows(const SonyArw6Plane &src, int rows)
+{
+  sony_arw6_require(rows >= 0 && rows <= src.rows);
+  SonyArw6Plane out(rows, src.cols);
+  if (rows)
+    memcpy(&out.data[0], &src.data[0],
+           sizeof(int32_t) * size_t(rows) * size_t(src.cols));
+  return out;
+}
+
+static SonyArw6Plane sony_arw6_inv53_axis0(const SonyArw6Plane &low,
+                                           const SonyArw6Plane &high)
+{
+  sony_arw6_require(low.rows == high.rows && low.cols == high.cols);
+  SonyArw6Plane lo2(low.rows, low.cols);
+  for (int y = 0; y < low.rows; y++)
+    for (int x = 0; x < low.cols; x++)
+    {
+      const int32_t hp = high.at(y ? y - 1 : 0, x);
+      const int32_t hc = high.at(y, x);
+      lo2.at(y, x) = low.at(y, x) - sony_arw6_floor_shift(hp + hc + 2, 2);
+    }
+
+  SonyArw6Plane out(low.rows * 2, low.cols);
+  for (int y = 0; y < low.rows; y++)
+    for (int x = 0; x < low.cols; x++)
+    {
+      const int32_t ln = lo2.at(y + 1 < low.rows ? y + 1 : y, x);
+      const int32_t hi2 =
+          high.at(y, x) + sony_arw6_floor_shift(lo2.at(y, x) + ln, 1);
+      out.at(y * 2, x) = lo2.at(y, x);
+      out.at(y * 2 + 1, x) = hi2;
+    }
+  return out;
+}
+
+static SonyArw6Plane sony_arw6_inv53_axis1(const SonyArw6Plane &low,
+                                           const SonyArw6Plane &high)
+{
+  sony_arw6_require(low.rows == high.rows && low.cols == high.cols);
+  SonyArw6Plane lo2(low.rows, low.cols);
+  for (int y = 0; y < low.rows; y++)
+    for (int x = 0; x < low.cols; x++)
+    {
+      const int32_t hp = high.at(y, x ? x - 1 : 0);
+      const int32_t hc = high.at(y, x);
+      lo2.at(y, x) = low.at(y, x) - sony_arw6_floor_shift(hp + hc + 2, 2);
+    }
+
+  SonyArw6Plane out(low.rows, low.cols * 2);
+  for (int y = 0; y < low.rows; y++)
+    for (int x = 0; x < low.cols; x++)
+    {
+      const int32_t ln = lo2.at(y, x + 1 < low.cols ? x + 1 : x);
+      const int32_t hi2 =
+          high.at(y, x) + sony_arw6_floor_shift(lo2.at(y, x) + ln, 1);
+      out.at(y, x * 2) = lo2.at(y, x);
+      out.at(y, x * 2 + 1) = hi2;
+    }
+  return out;
+}
+
+static SonyArw6Plane sony_arw6_inv53_axis0_high_leading(
+    const SonyArw6Plane &low, const SonyArw6Plane &high)
+{
+  sony_arw6_require(low.cols == high.cols);
+  sony_arw6_require(high.rows == low.rows || high.rows == low.rows + 1);
+  SonyArw6Plane lo2(low.rows, low.cols);
+  SonyArw6Plane hi2(high.rows, high.cols);
+
+  if (high.rows == low.rows + 1)
+  {
+    for (int y = 0; y < low.rows; y++)
+      for (int x = 0; x < low.cols; x++)
+        lo2.at(y, x) =
+            low.at(y, x) -
+            sony_arw6_floor_shift(high.at(y, x) + high.at(y + 1, x) + 2, 2);
+
+    for (int x = 0; x < high.cols; x++)
+    {
+      hi2.at(0, x) = high.at(0, x) + lo2.at(0, x);
+      hi2.at(high.rows - 1, x) = high.at(high.rows - 1, x) +
+                                 lo2.at(low.rows - 1, x);
+    }
+    for (int y = 1; y < high.rows - 1; y++)
+      for (int x = 0; x < high.cols; x++)
+        hi2.at(y, x) = high.at(y, x) +
+                       sony_arw6_floor_shift(lo2.at(y - 1, x) +
+                                                 lo2.at(y, x),
+                                             1);
+
+    SonyArw6Plane out(low.rows * 2 + 1, low.cols);
+    for (int y = 0; y < low.rows; y++)
+    {
+      memcpy(out.row(y * 2), hi2.row(y), sizeof(int32_t) * size_t(low.cols));
+      memcpy(out.row(y * 2 + 1), lo2.row(y),
+             sizeof(int32_t) * size_t(low.cols));
+    }
+    memcpy(out.row(out.rows - 1), hi2.row(hi2.rows - 1),
+           sizeof(int32_t) * size_t(low.cols));
+    return out;
+  }
+
+  for (int y = 0; y < low.rows; y++)
+    for (int x = 0; x < low.cols; x++)
+    {
+      const int next_y = y + 1 < high.rows ? y + 1 : y;
+      lo2.at(y, x) =
+          low.at(y, x) -
+          sony_arw6_floor_shift(high.at(y, x) + high.at(next_y, x) + 2, 2);
+    }
+  for (int x = 0; x < high.cols; x++)
+    hi2.at(0, x) = high.at(0, x) + lo2.at(0, x);
+  for (int y = 1; y < high.rows; y++)
+    for (int x = 0; x < high.cols; x++)
+      hi2.at(y, x) =
+          high.at(y, x) +
+          sony_arw6_floor_shift(lo2.at(y - 1, x) + lo2.at(y, x), 1);
+
+  SonyArw6Plane out(low.rows * 2, low.cols);
+  for (int y = 0; y < low.rows; y++)
+  {
+    memcpy(out.row(y * 2), hi2.row(y), sizeof(int32_t) * size_t(low.cols));
+    memcpy(out.row(y * 2 + 1), lo2.row(y),
+           sizeof(int32_t) * size_t(low.cols));
+  }
+  return out;
+}
+
+static SonyArw6Plane sony_arw6_synthesize_level(const SonyArw6Plane &ll,
+                                                const SonyArw6Plane &sub0,
+                                                const SonyArw6Plane &sub1,
+                                                const SonyArw6Plane &sub2)
+{
+  const int h = ll.rows;
+  const int w = ll.cols;
+  sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w);
+  sony_arw6_require(sub0.rows >= h + 1 && sub1.rows >= h + 1 &&
+                    sub2.rows >= h + 1);
+  SonyArw6Plane lh(h, w), hh(h, w);
+  for (int y = 0; y < h - 1; y++)
+    for (int x = 0; x < w; x++)
+    {
+      lh.at(y, x) = sub1.at(y + 1, x);
+      hh.at(y, x) = sub2.at(y + 1, x);
+    }
+  for (int x = 0; x < w; x++)
+  {
+    lh.at(h - 1, x) = sub0.at(h, x);
+    hh.at(h - 1, x) = sub1.at(h, x);
+  }
+  SonyArw6Plane low_horizontal = sony_arw6_inv53_axis0(ll, lh);
+  SonyArw6Plane high_horizontal =
+      sony_arw6_inv53_axis0(sony_arw6_head_rows(sub0, h), hh);
+  return sony_arw6_inv53_axis1(low_horizontal, high_horizontal);
+}
+
+static SonyArw6Plane sony_arw6_synthesize_guard_group1(
+    const SonyArw6Plane &ll, const SonyArw6Plane &sub0,
+    const SonyArw6Plane &sub1, const SonyArw6Plane &sub2)
+{
+  const int h = ll.rows;
+  const int w = ll.cols;
+  sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w);
+  sony_arw6_require(sub0.rows >= h + 2 && sub1.rows >= h + 2 &&
+                    sub2.rows >= h + 2);
+
+  SonyArw6Plane lh(h + 1, w), hh(h + 1, w), hl(h, w);
+  for (int y = 0; y < h; y++)
+    for (int x = 0; x < w; x++)
+    {
+      hl.at(y, x) = sub0.at(y + 1, x);
+      lh.at(y, x) = sub1.at(y + 1, x);
+      hh.at(y, x) = sub2.at(y + 1, x);
+    }
+  for (int x = 0; x < w; x++)
+  {
+    lh.at(h, x) = sub0.at(h + 1, x);
+    hh.at(h, x) = sub1.at(h + 1, x);
+  }
+
+  SonyArw6Plane low_horizontal =
+      sony_arw6_inv53_axis0_high_leading(ll, lh);
+  SonyArw6Plane high_horizontal =
+      sony_arw6_inv53_axis0_high_leading(hl, hh);
+  return sony_arw6_inv53_axis1(low_horizontal, high_horizontal);
+}
+
+static SonyArw6Plane sony_arw6_synthesize_guard_group2(
+    const SonyArw6Plane &ll, const SonyArw6Plane &sub0,
+    const SonyArw6Plane &sub1, const SonyArw6Plane &sub2,
+    bool odd_edge_mode)
+{
+  const int h = ll.rows;
+  const int w = ll.cols;
+  sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w);
+  sony_arw6_require(sub0.rows >= h + 3 && sub1.rows >= h + 1 &&
+                    sub2.rows >= h + 1);
+
+  SonyArw6Plane hl(h, w), lh(h, w), hh(h, w);
+  for (int x = 0; x < w; x++)
+  {
+    lh.at(0, x) = sub0.at(0, x);
+    hh.at(0, x) = sony_arw6_edge_detail(sub0.at(1, x), odd_edge_mode);
+  }
+  for (int y = 0; y < h; y++)
+    for (int x = 0; x < w; x++)
+      hl.at(y, x) = sub0.at(y + 2, x);
+  for (int y = 1; y < h; y++)
+    for (int x = 0; x < w; x++)
+    {
+      lh.at(y, x) = sub1.at(y + 1, x);
+      hh.at(y, x) = sub2.at(y + 1, x);
+    }
+
+  SonyArw6Plane low_horizontal =
+      sony_arw6_inv53_axis0_high_leading(ll, lh);
+  SonyArw6Plane high_horizontal =
+      sony_arw6_inv53_axis0_high_leading(hl, hh);
+  return sony_arw6_inv53_axis1(low_horizontal, high_horizontal);
+}
+
+static SonyArw6Plane sony_arw6_synthesize_guard_group3(
+    const SonyArw6Plane &ll, const SonyArw6Plane &sub0,
+    const SonyArw6Plane &sub1, const SonyArw6Plane &sub2,
+    bool odd_edge_mode)
+{
+  const int h = ll.rows;
+  const int w = ll.cols;
+  sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w);
+  sony_arw6_require(sub0.rows >= h + 5 && sub1.rows >= h + 2 &&
+                    sub2.rows >= h + 2);
+
+  SonyArw6Plane hl(h, w), lh(h, w), hh(h, w);
+  for (int x = 0; x < w; x++)
+  {
+    hl.at(0, x) = sub0.at(0, x);
+    lh.at(0, x) = sub0.at(1, x);
+    hh.at(0, x) = sony_arw6_edge_detail(sub0.at(2, x), odd_edge_mode);
+    lh.at(h - 1, x) = sub0.at(h + 3, x);
+    hh.at(h - 1, x) =
+        sony_arw6_edge_detail(sub0.at(h + 4, x), odd_edge_mode);
+  }
+  for (int y = 1; y < h; y++)
+    for (int x = 0; x < w; x++)
+      hl.at(y, x) = sub0.at(y + 3, x);
+  for (int y = 1; y < h - 1; y++)
+    for (int x = 0; x < w; x++)
+    {
+      lh.at(y, x) = sub1.at(y + 3, x);
+      hh.at(y, x) = sub2.at(y + 3, x);
+    }
+
+  SonyArw6Plane low_horizontal = sony_arw6_inv53_axis0(ll, lh);
+  SonyArw6Plane high_horizontal = sony_arw6_inv53_axis0(hl, hh);
+  return sony_arw6_inv53_axis1(low_horizontal, high_horizontal);
+}
+
+static SonyArw6Plane sony_arw6_synthesize_level_stride(
+    const SonyArw6Plane &ll, const SonyArw6Plane &sub0,
+    const SonyArw6Plane &sub1, const SonyArw6Plane &sub2, int edge_rows,
+    bool odd_edge_mode)
+{
+  if (edge_rows == 0)
+    return sony_arw6_synthesize_level(ll, sub0, sub1, sub2);
+
+  const int h = ll.rows;
+  const int w = ll.cols;
+  sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w);
+  sony_arw6_require(sub0.rows >= h + edge_rows * 2 &&
+                    sub1.rows >= h + edge_rows &&
+                    sub2.rows >= h);
+
+  SonyArw6Plane hl(h, w), lh(h, w), hh(h, w);
+  for (int y = 0; y < edge_rows; y++)
+    for (int x = 0; x < w; x++)
+    {
+      hl.at(y, x) = sub0.at(y, x);
+      lh.at(y, x) = sub0.at(y + edge_rows, x);
+      hh.at(y, x) = sony_arw6_edge_detail(sub1.at(y, x), odd_edge_mode);
+    }
+  for (int y = edge_rows; y < h - edge_rows; y++)
+    for (int x = 0; x < w; x++)
+    {
+      hl.at(y, x) = sub0.at(y + edge_rows, x);
+      lh.at(y, x) = sub1.at(y + edge_rows, x);
+      hh.at(y, x) = sub2.at(y + edge_rows, x);
+    }
+  for (int y = h - edge_rows; y < h; y++)
+  {
+    const int k = y - (h - edge_rows);
+    for (int x = 0; x < w; x++)
+    {
+      hl.at(y, x) = sub0.at(h + k, x);
+      lh.at(y, x) = sub0.at(h + edge_rows + k, x);
+      hh.at(y, x) = sony_arw6_edge_detail(sub1.at(h + k, x), odd_edge_mode);
+    }
+  }
+
+  SonyArw6Plane low_horizontal = sony_arw6_inv53_axis0(ll, lh);
+  SonyArw6Plane high_horizontal = sony_arw6_inv53_axis0(hl, hh);
+  return sony_arw6_inv53_axis1(low_horizontal, high_horizontal);
+}
+
+static SonyArw6Plane sony_arw6_final_green(const SonyArw6Plane &ll,
+                                           const SonyArw6Plane &detail,
+                                           int top_rows)
+{
+  const int h = ll.rows;
+  const int w = ll.cols;
+  sony_arw6_require(top_rows >= 0 && top_rows <= 8);
+  sony_arw6_require(detail.cols == w &&
+                    detail.rows >= 8 + std::max(0, h - top_rows));
+
+  SonyArw6Plane selected(h, w);
+  for (int y = 0; y < h; y++)
+  {
+    const int src_y = y < top_rows ? y : y + 8 - top_rows;
+    for (int x = 0; x < w; x++)
+      selected.at(y, x) = detail.at(src_y, x);
+  }
+
+  SonyArw6Plane odd_green(h, w);
+  for (int y = 0; y < h; y++)
+  {
+    const int prev_y = y ? y - 1 : y;
+    for (int x = 0; x < w; x++)
+    {
+      int32_t pred;
+      if (x + 1 < w)
+        pred = sony_arw6_floor_shift(
+            selected.at(y, x + 1) + selected.at(prev_y, x) +
+                selected.at(y, x) + selected.at(prev_y, x + 1),
+            2);
+      else
+        pred = sony_arw6_floor_shift(
+            (selected.at(prev_y, x) + selected.at(y, x)) * 2, 2);
+      odd_green.at(y, x) =
+          sony_arw6_floor_shift(int64_t(2) * ll.at(y, x) - pred, 1);
+    }
+  }
+
+  SonyArw6Plane even_green(h, w);
+  for (int y = 0; y < h; y++)
+  {
+    const int next_y = y + 1 < h ? y + 1 : y;
+    even_green.at(y, 0) =
+        selected.at(y, 0) +
+        sony_arw6_floor_shift((odd_green.at(y, 0) + odd_green.at(next_y, 0)) *
+                                  int64_t(2),
+                              2);
+    for (int x = 1; x < w; x++)
+      even_green.at(y, x) =
+          selected.at(y, x) +
+          sony_arw6_floor_shift(odd_green.at(y, x - 1) +
+                                    odd_green.at(next_y, x - 1) +
+                                    odd_green.at(next_y, x) +
+                                    odd_green.at(y, x),
+                                2);
+  }
+
+  SonyArw6Plane out(h, w * 2);
+  for (int y = 0; y < h; y++)
+    for (int x = 0; x < w; x++)
+    {
+      out.at(y, x * 2) = even_green.at(y, x);
+      out.at(y, x * 2 + 1) = odd_green.at(y, x);
+    }
+  return out;
+}
+
+static inline ushort sony_arw6_sample_from_signed(int32_t x)
+{
+  int code = x + SONY_ARW6_INTERNAL_BIAS;
+  if (code < 0)
+    code = 0;
+  if (code > 4095)
+    code = 4095;
+  return sony_arw6_llvc3_lut_value(code);
+}
+
+static inline int32_t sony_arw6_clamp_signed_code(int32_t x)
+{
+  int code = x + SONY_ARW6_INTERNAL_BIAS;
+  if (code < 0)
+    code = 0;
+  if (code > 4095)
+    code = 4095;
+  return code - SONY_ARW6_INTERNAL_BIAS;
+}
+
+struct SonyArw6DecodedTile
+{
+  SonyArw6Plane green;
+  SonyArw6Plane red_residual;
+  SonyArw6Plane blue_residual;
+  SonyArw6Plane full_green;
+};
+
+static SonyArw6DecodedTile sony_arw6_decode_stream_tile(const uchar *stream,
+                                                        uint32_t stream_size)
+{
+  SonyArw6StreamInfo header;
+  sony_arw6_require(sony_arw6_parse_stream_header(stream, stream_size, header));
+  const std::vector<SonyArw6DirectoryEntry> dir =
+      sony_arw6_parse_directory(stream, stream_size);
+  const int coded_height = header.logical_height;
+  sony_arw6_require(header.coded_width > 0 && coded_height > 0);
+  const int padded_height = sony_arw6_align_up(coded_height, 16);
+  const bool guarded_height = coded_height != padded_height;
+  const int low_rows = padded_height / 16;
+  const int low_start = guarded_height ? 1 : 0;
+  const int low_count = low_rows - low_start;
+
+  std::vector<SonyArw6Plane> g0 =
+      sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                     header.coded_width, coded_height, 0, 0);
+  SonyArw6Plane green =
+      sony_arw6_integrate_type1(g0[0], low_start + low_count, 0);
+  if (low_start)
+  {
+    SonyArw6Plane cropped(low_count, green.cols);
+    for (int y = 0; y < low_count; y++)
+      memcpy(cropped.row(y), green.row(y + low_start),
+             sizeof(int32_t) * size_t(green.cols));
+    green = cropped;
+  }
+
+  std::vector<SonyArw6Plane> r0 =
+      sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                     header.coded_width, coded_height, 0, 1);
+  SonyArw6Plane red_residual =
+      sony_arw6_integrate_type1(r0[0], low_start + low_count, 0);
+  if (low_start)
+  {
+    SonyArw6Plane cropped(low_count, red_residual.cols);
+    for (int y = 0; y < low_count; y++)
+      memcpy(cropped.row(y), red_residual.row(y + low_start),
+             sizeof(int32_t) * size_t(red_residual.cols));
+    red_residual = cropped;
+  }
+
+  std::vector<SonyArw6Plane> b0 =
+      sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                     header.coded_width, coded_height, 0, 2);
+  SonyArw6Plane blue_residual =
+      sony_arw6_integrate_type1(b0[0], low_start + low_count, 0);
+  if (low_start)
+  {
+    SonyArw6Plane cropped(low_count, blue_residual.cols);
+    for (int y = 0; y < low_count; y++)
+      memcpy(cropped.row(y), blue_residual.row(y + low_start),
+             sizeof(int32_t) * size_t(blue_residual.cols));
+    blue_residual = cropped;
+  }
+
+  for (int group = 1; group <= 3; group++)
+  {
+    const int edge_rows = group == 1 ? 0 : (group == 2 ? 1 : 2);
+    const bool color_odd_edge = group == 3;
+
+    std::vector<SonyArw6Plane> planes =
+        sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                       header.coded_width, coded_height, group,
+                                       0);
+    if (guarded_height)
+    {
+      if (group == 1)
+        green = sony_arw6_synthesize_guard_group1(green, planes[0],
+                                                  planes[1], planes[2]);
+      else if (group == 2)
+        green = sony_arw6_synthesize_guard_group2(green, planes[0],
+                                                  planes[1], planes[2], false);
+      else
+        green = sony_arw6_synthesize_guard_group3(green, planes[0],
+                                                  planes[1], planes[2], false);
+    }
+    else
+      green = sony_arw6_synthesize_level_stride(green, planes[0], planes[1],
+                                                planes[2], edge_rows, false);
+
+    planes = sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                            header.coded_width, coded_height,
+                                            group, 1);
+    if (guarded_height)
+    {
+      if (group == 1)
+        red_residual = sony_arw6_synthesize_guard_group1(
+            red_residual, planes[0], planes[1], planes[2]);
+      else if (group == 2)
+        red_residual = sony_arw6_synthesize_guard_group2(
+            red_residual, planes[0], planes[1], planes[2], false);
+      else
+        red_residual = sony_arw6_synthesize_guard_group3(
+            red_residual, planes[0], planes[1], planes[2], color_odd_edge);
+    }
+    else
+      red_residual = sony_arw6_synthesize_level_stride(
+          red_residual, planes[0], planes[1], planes[2], edge_rows,
+          color_odd_edge);
+
+    planes = sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                            header.coded_width, coded_height,
+                                            group, 2);
+    if (guarded_height)
+    {
+      if (group == 1)
+        blue_residual = sony_arw6_synthesize_guard_group1(
+            blue_residual, planes[0], planes[1], planes[2]);
+      else if (group == 2)
+        blue_residual = sony_arw6_synthesize_guard_group2(
+            blue_residual, planes[0], planes[1], planes[2], false);
+      else
+        blue_residual = sony_arw6_synthesize_guard_group3(
+            blue_residual, planes[0], planes[1], planes[2], color_odd_edge);
+    }
+    else
+      blue_residual = sony_arw6_synthesize_level_stride(
+          blue_residual, planes[0], planes[1], planes[2], edge_rows,
+          color_odd_edge);
+  }
+
+  std::vector<SonyArw6Plane> g4 =
+      sony_arw6_decode_packet_arrays(stream, stream_size, dir,
+                                     header.coded_width, coded_height, 4, 0);
+  SonyArw6Plane full_green =
+      sony_arw6_final_green(green, g4[0], guarded_height ? 2 : 4);
+
+  SonyArw6DecodedTile out;
+  out.green = green;
+  out.red_residual = red_residual;
+  out.blue_residual = blue_residual;
+  out.full_green = full_green;
+  return out;
+}
+
+} // namespace
+
+void LibRaw::sony_arw6_load_raw()
+{
+  if (raw_width <= 0 || raw_height <= 0 || (raw_width & 15) ||
+      (raw_height & 1))
+    throw LIBRAW_EXCEPTION_IO_BADFILE;
+  if (!raw_image)
+    throw LIBRAW_EXCEPTION_IO_BADFILE;
+  if (data_size < SONY_ARW6_STREAM_OFFSET + 0x80 ||
+      data_size > 1024LL * 1024LL * 1024LL)
+    throw LIBRAW_EXCEPTION_IO_CORRUPT;
+  if (data_size > INT64(imgdata.rawparams.max_raw_memory_mb) *
+                      INT64(1024 * 1024))
+    throw LIBRAW_EXCEPTION_ALLOC;
+
+  std::vector<uchar> strip(size_t(data_size));
+  ifp->seek(data_offset, SEEK_SET);
+  const int readed = ifp->read(&strip[0], 1, size_t(data_size));
+  if (readed != data_size)
+    throw LIBRAW_EXCEPTION_IO_EOF;
+
+  const std::vector<SonyArw6StreamInfo> streams =
+      sony_arw6_find_streams(strip, raw_width, raw_height);
+  sony_arw6_require(!streams.empty());
+
+  INT64 max_tile_pixels = 0;
+  for (size_t si = 0; si < streams.size(); si++)
+  {
+    const SonyArw6StreamInfo &s = streams[si];
+    max_tile_pixels =
+        std::max(max_tile_pixels, INT64(s.coded_width) * s.logical_height);
+  }
+  const INT64 raw_bytes = INT64(raw_width) * raw_height *
+                          INT64(sizeof(raw_image[0]));
+  const INT64 working_bytes =
+      raw_bytes + data_size +
+      max_tile_pixels * SONY_ARW6_WORKING_BYTES_PER_TILE_PIXEL;
+  if (working_bytes > sony_arw6_memory_limit_bytes(
+                          imgdata.rawparams.max_raw_memory_mb))
+    throw LIBRAW_EXCEPTION_ALLOC;
+
+  for (size_t si = 0; si < streams.size(); si++)
+  {
+    checkCancel();
+    const SonyArw6StreamInfo &s = streams[si];
+    sony_arw6_require(s.offset <= strip.size() &&
+                      s.length <= strip.size() - s.offset);
+    sony_arw6_require(s.tile_x >= 0 && s.tile_y >= 0 &&
+                      s.tile_w == s.coded_width &&
+                      s.tile_h == s.logical_height &&
+                      s.tile_x + s.tile_w <= raw_width &&
+                      s.tile_y + s.tile_h <= raw_height);
+
+    SonyArw6DecodedTile tile =
+        sony_arw6_decode_stream_tile(&strip[s.offset], s.length);
+
+    const int half_h = s.logical_height / 2;
+    const int half_w = s.coded_width / 2;
+    sony_arw6_require(tile.full_green.rows >= half_h &&
+                      tile.full_green.cols == s.coded_width);
+    sony_arw6_require(tile.green.rows >= half_h &&
+                      tile.green.cols == half_w);
+    sony_arw6_require(tile.red_residual.rows >= half_h &&
+                      tile.red_residual.cols == half_w);
+    sony_arw6_require(tile.blue_residual.rows >= half_h &&
+                      tile.blue_residual.cols == half_w);
+
+    for (int y = 0; y < half_h; y++)
+    {
+      checkCancel();
+      ushort *row0 =
+          raw_image + size_t(s.tile_y + y * 2) * raw_width + s.tile_x;
+      ushort *row1 =
+          raw_image + size_t(s.tile_y + y * 2 + 1) * raw_width + s.tile_x;
+      for (int x = 0; x < half_w; x++)
+      {
+        const int32_t g0 =
+            sony_arw6_clamp_signed_code(tile.full_green.at(y, x * 2));
+        const int32_t g1 =
+            sony_arw6_clamp_signed_code(tile.full_green.at(y, x * 2 + 1));
+        const int32_t gavg = sony_arw6_floor_shift(int64_t(g0) + g1, 1);
+        row0[x * 2] = sony_arw6_sample_from_signed(
+            gavg + 2 * tile.red_residual.at(y, x));
+        row0[x * 2 + 1] =
+            sony_arw6_sample_from_signed(tile.full_green.at(y, x * 2 + 1));
+        row1[x * 2] =
+            sony_arw6_sample_from_signed(tile.full_green.at(y, x * 2));
+        row1[x * 2 + 1] = sony_arw6_sample_from_signed(
+            gavg + 2 * tile.blue_residual.at(y, x));
+      }
+    }
+  }
+}
diff --git a/core/libs/rawengine/libraw/src/metadata/canon.cpp b/core/libs/rawengine/libraw/src/metadata/canon.cpp
index 5def57dfc4..f6007dcedc 100644
--- a/core/libs/rawengine/libraw/src/metadata/canon.cpp
+++ b/core/libs/rawengine/libraw/src/metadata/canon.cpp
@@ -131,6 +131,7 @@ void LibRaw::setCanonBodyFeatures(unsigned long long id)
               (id == CanonID_EOS_R7)
            || (id == CanonID_EOS_R10)
            || (id == CanonID_EOS_R50)
+           || (id == CanonID_EOS_R50_V)
            || (id == CanonID_EOS_R100)
           )
   {
@@ -1308,7 +1309,7 @@ void LibRaw::parseCanonMakernotes(unsigned tag, unsigned type, unsigned len, uns
       break;
 
     case 3973: // R3; ColorDataSubVer: 34
-    case 3778: // R6 Mark II, R7, R8, R10, R50; ColorDataSubVer: 48
+    case 3778: // R6 Mark II, R7, R8, R10, R50, R50 V; ColorDataSubVer: 48
       imCanon.ColorDataVer = 11;
       AsShot_Auto_MeasuredWB(0x0069);
 
diff --git a/core/libs/rawengine/libraw/src/metadata/identify.cpp b/core/libs/rawengine/libraw/src/metadata/identify.cpp
index 014488b8aa..3b967c8467 100644
--- a/core/libs/rawengine/libraw/src/metadata/identify.cpp
+++ b/core/libs/rawengine/libraw/src/metadata/identify.cpp
@@ -3139,7 +3139,7 @@ void LibRaw::identify_finetune_dcr(char head[64], INT64 fsize, INT64 flen)
 
 		  /* need samples for lossy small/medium w/ APC crop*/
         }
-        else if ((unique_id == SonyID_ILCE_7M4)|| (unique_id == SonyID_ILCE_7CM2) || (unique_id == SonyID_ILME_FX2))
+        else if ((unique_id == SonyID_ILCE_7M4) || (unique_id == SonyID_ILCE_7CM2) || (unique_id == SonyID_ILME_FX2) || (unique_id == SonyID_ILCE_7M5))
         {
           if (raw_width == 7168 && raw_height == 5120) 
           {
diff --git a/core/libs/rawengine/libraw/src/metadata/normalize_model.cpp b/core/libs/rawengine/libraw/src/metadata/normalize_model.cpp
index c8b65acac9..23c69ec535 100644
--- a/core/libs/rawengine/libraw/src/metadata/normalize_model.cpp
+++ b/core/libs/rawengine/libraw/src/metadata/normalize_model.cpp
@@ -107,6 +107,7 @@ void LibRaw::GetNormalizedModel()
       { CanonID_EOS_R7,            "EOS R7"},
       { CanonID_EOS_R10,           "EOS R10"},
       { CanonID_EOS_M50_Mark_II,   "EOS M50 Mark II"}, // M50m2, Kiss M2
+      { CanonID_EOS_R50_V,         "EOS R50 V"},
       { CanonID_EOS_R50,           "EOS R50"},
       { CanonID_EOS_R6m2,          "EOS R6 Mark II"},
       { CanonID_EOS_R8,            "EOS R8"},
@@ -399,6 +400,7 @@ void LibRaw::GetNormalizedModel()
       { SonyID_ILX_LR1,        "ILX-LR1"},
       { SonyID_ZV_E10M2,       "ZV-E10M2"},
       { SonyID_ILME_FX2,       "ILME-FX2"},
+      { SonyID_ILCE_7M5,       "ILCE-7M5"},
 };
 
   static const char *orig;
diff --git a/core/libs/rawengine/libraw/src/metadata/sony.cpp b/core/libs/rawengine/libraw/src/metadata/sony.cpp
index bdc36080f9..1b0c0837b4 100644
--- a/core/libs/rawengine/libraw/src/metadata/sony.cpp
+++ b/core/libs/rawengine/libraw/src/metadata/sony.cpp
@@ -364,6 +364,8 @@ void LibRaw::setSonyBodyFeatures(unsigned long long id) {
        LIBRAW_SONY_Tag2010None, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
       {SonyID_ZV_E10M2, sbfILCE_DX,
        LIBRAW_SONY_Tag2010None, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
+      {SonyID_ILCE_7M5, sbfILCE_FF,
+       LIBRAW_SONY_Tag2010None, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
   };
   ilm.CamID = id;
   int isPreProductionFW = 0;
@@ -454,6 +456,7 @@ void LibRaw::setSonyBodyFeatures(unsigned long long id) {
   case SonyID_ILCE_7CR:
   case SonyID_ILCE_7CM2:
   case SonyID_ILCE_9M3:
+  case SonyID_ILCE_7M5:
   case SonyID_ZV_E10M2:
     imSony.group9050 = LIBRAW_SONY_Tag9050d;
     break;
@@ -956,7 +959,7 @@ void LibRaw::process_Sony_0x9400(uchar *buf, ushort len, unsigned long long /*id
     FORC4 s[c] = SonySubstitution[buf[0x1a + c]];
     imSony.Sony0x9400_SequenceFileNumber = sget4(s);
 
-    imSony.Sony0x9400_SequenceLength2 = SonySubstitution[buf[0x1e]]; // files
+    imSony.Sony0x9400_SequenceLength2 = SonySubstitution[buf[0x1e]]; // files //ilce-7m5 modifed here
   }
 
   else if ((bufx == 0x0c) && (len >= 0x1f)) // 0x9400 'b' version
diff --git a/core/libs/rawengine/libraw/src/metadata/tiff.cpp b/core/libs/rawengine/libraw/src/metadata/tiff.cpp
index c129cd3f3e..bad650531f 100644
--- a/core/libs/rawengine/libraw/src/metadata/tiff.cpp
+++ b/core/libs/rawengine/libraw/src/metadata/tiff.cpp
@@ -2074,6 +2074,17 @@ void LibRaw::apply_tiff()
   if (raw >= 0 && !load_raw)
     switch (tiff_compress)
     {
+    case 32766:
+      if (!dng_version && !strncasecmp(make, "Sony", 4) &&
+          tiff_ifd[raw].phint == 32803 && tiff_ifd[raw].samples == 1 &&
+          (tiff_bps == 12 || tiff_bps == 14) && raw_width > 0 &&
+          raw_height > 0)
+      {
+        load_raw = &LibRaw::sony_arw6_load_raw;
+        tiff_bps = 14;
+        break;
+      }
+      break;
     case 32767:
       if (!dng_version &&
           tiff_ifd[raw].bytes == INT64(raw_width) * INT64(raw_height))
diff --git a/core/libs/rawengine/libraw/src/tables/cameralist.cpp b/core/libs/rawengine/libraw/src/tables/cameralist.cpp
index 3478a77877..9492de9917 100644
--- a/core/libs/rawengine/libraw/src/tables/cameralist.cpp
+++ b/core/libs/rawengine/libraw/src/tables/cameralist.cpp
@@ -161,6 +161,7 @@ static const char *static_camera_list[] = {
 	"Canon EOS R7",
 	"Canon EOS R8",
 	"Canon EOS R10",
+	"Canon EOS R50 V",
 	"Canon EOS R50",
 	"Canon EOS R100",
 	"Canon EOS D30",
@@ -1183,6 +1184,7 @@ static const char *static_camera_list[] = {
 	"Sony ILCE-7M2 (A7 II)",
 	"Sony ILCE-7M3 (A7 III)",
 	"Sony ILCE-7M4 (A7 IV)",
+	"Sony ILCE-7M5 (A7 V)",
 	"Sony ILCE-7C (A7C)",
 	"Sony ILCE-7CR (A7CR)",
 	"Sony ILCE-7CM2 (A7C II)",
diff --git a/core/libs/rawengine/libraw/src/tables/colordata.cpp b/core/libs/rawengine/libraw/src/tables/colordata.cpp
index 8e04141dc7..3f6dc81ce0 100644
--- a/core/libs/rawengine/libraw/src/tables/colordata.cpp
+++ b/core/libs/rawengine/libraw/src/tables/colordata.cpp
@@ -147,6 +147,8 @@ int LibRaw::adobe_coeff(unsigned make_idx, const char *t_model,
 	  { 8608,-2097,-1178,-5425,13265,2383,-1149,2238,5680 } },
 	{ LIBRAW_CAMERAMAKER_Canon, "EOS R3", 0, 0,
 	  { 9423,-2839,-1195,-4532,12377,2415,-483,1374,5276 } },
+	{ LIBRAW_CAMERAMAKER_Canon, "EOS R50 V", 0, 0,
+	  { 9089, -1810, -1209, -4294, 12116, 2454, -498, 1862, 4923 } },
 	{ LIBRAW_CAMERAMAKER_Canon, "EOS R50", 0, 0,
 	  {  9269, -2012, -1107, -3990, 11762,  2527,  -569,  2093,  4913 } },
 	{ LIBRAW_CAMERAMAKER_Canon, "EOS R100", 0, 0,
@@ -1770,7 +1772,9 @@ int LibRaw::adobe_coeff(unsigned make_idx, const char *t_model,
       { 7460,-2365,-588,-5687,13442,2474,-624,1156,6584 } },
     { LIBRAW_CAMERAMAKER_Sony, "ILCE-7C", 0, 0,
       { 7374,-2389,-551,-5435,13162,2519,-1006,1795,6552 } },
-
+	  
+    { LIBRAW_CAMERAMAKER_Sony, "ILCE-7M5", 0, 0,
+      { 9089, -3577, -787, -3563, 11326, 2557, -114, 928, 5904 } },
     { LIBRAW_CAMERAMAKER_Sony, "ILCE-7M4", 0, 0,
       { 7460,-2365,-588,-5687,13442,2474,-624,1156,6584 } },
     { LIBRAW_CAMERAMAKER_Sony, "ILCE-7M3", 0, 0,
diff --git a/core/libs/rawengine/libraw/src/utils/decoder_info.cpp b/core/libs/rawengine/libraw/src/utils/decoder_info.cpp
index c5c902d789..f92b531d15 100644
--- a/core/libs/rawengine/libraw/src/utils/decoder_info.cpp
+++ b/core/libs/rawengine/libraw/src/utils/decoder_info.cpp
@@ -317,6 +317,11 @@ int LibRaw::get_decoder_info(libraw_decoder_info_t *d_info)
                             LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_TRYRAWSPEED3 |
                             LIBRAW_DECODER_SONYARW2;
   }
+  else if (load_raw == &LibRaw::sony_arw6_load_raw)
+  {
+    d_info->decoder_name = "sony_arw6_load_raw()";
+    d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC;
+  }
   else if (load_raw == &LibRaw::sony_arq_load_raw)
   {
     d_info->decoder_name = "sony_arq_load_raw()";
diff --git a/core/libs/rawengine/libraw/src/utils/open.cpp b/core/libs/rawengine/libraw/src/utils/open.cpp
index ffd439eb15..ed1c379be9 100644
--- a/core/libs/rawengine/libraw/src/utils/open.cpp
+++ b/core/libs/rawengine/libraw/src/utils/open.cpp
@@ -1073,6 +1073,17 @@ int LibRaw::open_datastream(LibRaw_abstract_datastream *stream)
               S.raw_width == 2816) // A7S2=> exact, hope it works for A7S-I too
       )
         S.width = S.raw_width - 32;
+
+      if (load_raw == &LibRaw::sony_arw6_load_raw)
+      {
+        /* it would be great to get it via metadata */
+        C.black = 1024;
+        for (int c = 0; c < 6; c++)
+          C.cblack[c] = 0;
+        C.maximum = 39002; // last curve item
+        for (int c = 0; c < 4; c++)
+          C.linear_max[c] = 32800;
+      }
     }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.