{
    "file_diffs": [
        {
            "old_file_content": "import pytest\n\nfrom PIL import Image\n\nfrom .helper import hopper\n\nTEST_FILE = \"Tests/images/hopper.ppm\"\n\nORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS\n\n\nclass TestDecompressionBomb:\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def test_no_warning_small_file(self):\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_no_warning_no_limit(self):\n        # Arrange\n        # Turn limit off\n        Image.MAX_IMAGE_PIXELS = None\n        assert Image.MAX_IMAGE_PIXELS is None\n\n        # Act / Assert\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_warning(self):\n        # Set limit to trigger warning on the test file\n        Image.MAX_IMAGE_PIXELS = 128 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1\n\n        def open():\n            with Image.open(TEST_FILE):\n                pass\n\n        pytest.warns(Image.DecompressionBombWarning, open)\n\n    def test_exception(self):\n        # Set limit to trigger exception on the test file\n        Image.MAX_IMAGE_PIXELS = 64 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1\n\n        with pytest.raises(Image.DecompressionBombError):\n            with Image.open(TEST_FILE):\n                pass\n\n    def test_exception_ico(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.ico\")\n\n    def test_exception_gif(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.gif\")\n\n\nclass TestDecompressionCrop:\n    @classmethod\n    def setup_class(self):\n        width, height = 128, 128\n        Image.MAX_IMAGE_PIXELS = height * width * 4 - 1\n\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def testEnlargeCrop(self):\n        # Crops can extend the extents, therefore we should have the\n        # same decompression bomb warnings on them.\n        with hopper() as src:\n            box = (0, 0, src.width * 2, src.height * 2)\n            pytest.warns(Image.DecompressionBombWarning, src.crop, box)\n\n    def test_crop_decompression_checks(self):\n\n        im = Image.new(\"RGB\", (100, 100))\n\n        good_values = ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990))\n\n        warning_values = ((-160, -160, 99, 99), (160, 160, -99, -99))\n\n        error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))\n\n        for value in good_values:\n            assert im.crop(value).size == (9, 9)\n\n        for value in warning_values:\n            pytest.warns(Image.DecompressionBombWarning, im.crop, value)\n\n        for value in error_values:\n            with pytest.raises(Image.DecompressionBombError):\n                im.crop(value)\n",
            "new_file_content": "import pytest\n\nfrom PIL import Image\n\nfrom .helper import hopper\n\nTEST_FILE = \"Tests/images/hopper.ppm\"\n\nORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS\n\n\nclass TestDecompressionBomb:\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def test_no_warning_small_file(self):\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_no_warning_no_limit(self):\n        # Arrange\n        # Turn limit off\n        Image.MAX_IMAGE_PIXELS = None\n        assert Image.MAX_IMAGE_PIXELS is None\n\n        # Act / Assert\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_warning(self):\n        # Set limit to trigger warning on the test file\n        Image.MAX_IMAGE_PIXELS = 128 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1\n\n        def open():\n            with Image.open(TEST_FILE):\n                pass\n\n        pytest.warns(Image.DecompressionBombWarning, open)\n\n    def test_exception(self):\n        # Set limit to trigger exception on the test file\n        Image.MAX_IMAGE_PIXELS = 64 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1\n\n        with pytest.raises(Image.DecompressionBombError):\n            with Image.open(TEST_FILE):\n                pass\n\n    def test_exception_ico(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.ico\")\n\n    def test_exception_gif(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.gif\")\n\n    def test_exception_bmp(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/bmp/b/reallybig.bmp\")\n\n\nclass TestDecompressionCrop:\n    @classmethod\n    def setup_class(self):\n        width, height = 128, 128\n        Image.MAX_IMAGE_PIXELS = height * width * 4 - 1\n\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def testEnlargeCrop(self):\n        # Crops can extend the extents, therefore we should have the\n        # same decompression bomb warnings on them.\n        with hopper() as src:\n            box = (0, 0, src.width * 2, src.height * 2)\n            pytest.warns(Image.DecompressionBombWarning, src.crop, box)\n\n    def test_crop_decompression_checks(self):\n\n        im = Image.new(\"RGB\", (100, 100))\n\n        good_values = ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990))\n\n        warning_values = ((-160, -160, 99, 99), (160, 160, -99, -99))\n\n        error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))\n\n        for value in good_values:\n            assert im.crop(value).size == (9, 9)\n\n        for value in warning_values:\n            pytest.warns(Image.DecompressionBombWarning, im.crop, value)\n\n        for value in error_values:\n            with pytest.raises(Image.DecompressionBombError):\n                im.crop(value)\n",
            "header": {
                "file": {
                    "path": "Tests/test_decompression_bomb.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "5799fc0ed",
                "new_commit_hash": "132269933",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_decompression_bomb.py"
            },
            "plus_file": {
                "path": "b/Tests/test_decompression_bomb.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 60,
                            "length": 6
                        },
                        "new_range": {
                            "start": 60,
                            "length": 10
                        },
                        "section": "class TestDecompressionBomb:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        with pytest.raises(Image.DecompressionBombError):",
                                "type": "context"
                            },
                            {
                                "content": "            Image.open(\"Tests/images/decompression_bomb.gif\")",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_exception_bmp(self):",
                                "type": "added"
                            },
                            {
                                "content": "        with pytest.raises(Image.DecompressionBombError):",
                                "type": "added"
                            },
                            {
                                "content": "            Image.open(\"Tests/images/bmp/b/reallybig.bmp\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class TestDecompressionCrop:",
                                "type": "context"
                            },
                            {
                                "content": "    @classmethod",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_decompression_bomb.py",
                            "type": "class",
                            "name": "TestDecompressionBomb",
                            "content": "class TestDecompressionBomb:\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def test_no_warning_small_file(self):\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_no_warning_no_limit(self):\n        # Arrange\n        # Turn limit off\n        Image.MAX_IMAGE_PIXELS = None\n        assert Image.MAX_IMAGE_PIXELS is None\n\n        # Act / Assert\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_warning(self):\n        # Set limit to trigger warning on the test file\n        Image.MAX_IMAGE_PIXELS = 128 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1\n\n        def open():\n            with Image.open(TEST_FILE):\n                pass\n\n        pytest.warns(Image.DecompressionBombWarning, open)\n\n    def test_exception(self):\n        # Set limit to trigger exception on the test file\n        Image.MAX_IMAGE_PIXELS = 64 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1\n\n        with pytest.raises(Image.DecompressionBombError):\n            with Image.open(TEST_FILE):\n                pass\n\n    def test_exception_ico(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.ico\")\n\n    def test_exception_gif(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.gif\")\n\n    def test_exception_bmp(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/bmp/b/reallybig.bmp\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 12,
                            "end_lineno": 65,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Tests/test_decompression_bomb.py",
                            "type": "method",
                            "name": "TestDecompressionBomb.test_exception_bmp",
                            "content": "class TestDecompressionBomb:\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def test_no_warning_small_file(self):\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_no_warning_no_limit(self):\n        # Arrange\n        # Turn limit off\n        Image.MAX_IMAGE_PIXELS = None\n        assert Image.MAX_IMAGE_PIXELS is None\n\n        # Act / Assert\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_warning(self):\n        # Set limit to trigger warning on the test file\n        Image.MAX_IMAGE_PIXELS = 128 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1\n\n        def open():\n            with Image.open(TEST_FILE):\n                pass\n\n        pytest.warns(Image.DecompressionBombWarning, open)\n\n    def test_exception(self):\n        # Set limit to trigger exception on the test file\n        Image.MAX_IMAGE_PIXELS = 64 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1\n\n        with pytest.raises(Image.DecompressionBombError):\n            with Image.open(TEST_FILE):\n                pass\n\n    def test_exception_ico(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.ico\")\n\n    def test_exception_gif(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.gif\")\n\n    def test_exception_bmp(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/bmp/b/reallybig.bmp\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 63,
                            "end_lineno": 65,
                            "parent": {
                                "file_name": "Tests/test_decompression_bomb.py",
                                "type": "class",
                                "name": "TestDecompressionBomb",
                                "content": "class TestDecompressionBomb:\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def test_no_warning_small_file(self):\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_no_warning_no_limit(self):\n        # Arrange\n        # Turn limit off\n        Image.MAX_IMAGE_PIXELS = None\n        assert Image.MAX_IMAGE_PIXELS is None\n\n        # Act / Assert\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_warning(self):\n        # Set limit to trigger warning on the test file\n        Image.MAX_IMAGE_PIXELS = 128 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1\n\n        def open():\n            with Image.open(TEST_FILE):\n                pass\n\n        pytest.warns(Image.DecompressionBombWarning, open)\n\n    def test_exception(self):\n        # Set limit to trigger exception on the test file\n        Image.MAX_IMAGE_PIXELS = 64 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1\n\n        with pytest.raises(Image.DecompressionBombError):\n            with Image.open(TEST_FILE):\n                pass\n\n    def test_exception_ico(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.ico\")\n\n    def test_exception_gif(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.gif\")\n\n    def test_exception_bmp(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/bmp/b/reallybig.bmp\")",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 12,
                                "end_lineno": 65,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "8.0.0\n-----\n\nBackwards Incompatible Changes\n==============================\n\nPython 3.5\n^^^^^^^^^^\n\nPillow has dropped support for Python 3.5, which reached end-of-life on 2020-09-13.\n\nim.offset\n^^^^^^^^^\n\n``im.offset()`` has been removed, call :py:func:`.ImageChops.offset()` instead.\n\nImage.fromstring, im.fromstring and im.tostring\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n* ``Image.fromstring()`` has been removed, call :py:func:`.Image.frombytes()` instead.\n* ``im.fromstring()`` has been removed, call :py:meth:`~PIL.Image.Image.frombytes()` instead.\n* ``im.tostring()`` has been removed, call :py:meth:`~PIL.Image.Image.tobytes()` instead.\n\nImageCms.CmsProfile attributes\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nSome attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed:\n\n========================  ===================================================\nRemoved                   Use instead\n========================  ===================================================\n``color_space``           Padded :py:attr:`~.CmsProfile.xcolor_space`\n``pcs``                   Padded :py:attr:`~.CmsProfile.connection_space`\n``product_copyright``     Unicode :py:attr:`~.CmsProfile.copyright`\n``product_desc``          Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_description``   Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_manufacturer``  Unicode :py:attr:`~.CmsProfile.manufacturer`\n``product_model``         Unicode :py:attr:`~.CmsProfile.model`\n========================  ===================================================\n\nAPI Changes\n===========\n\nAdd MIME type to PsdImagePlugin\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\"image/vnd.adobe.photoshop\" is now registered as the\n:py:class:`.PsdImagePlugin.PsdImageFile` MIME type.\n\nAPI Additions\n=============\n\nImage.open: add formats parameter\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAdded a new ``formats`` parameter to :py:func:`.Image.open`:\n\n* A list or tuple of formats to attempt to load the file in.\n  This can be used to restrict the set of formats checked.\n  Pass ``None`` to try all supported formats. You can print the set of\n  available formats by running ``python -m PIL`` or using\n  the :py:func:`PIL.features.pilinfo` function.\n\nImageOps.autocontrast: add mask parameter\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n:py:func:`.ImageOps.autocontrast` can now take a ``mask`` parameter:\n\n* Histogram used in contrast operation is computed using pixels within the mask.\n  If no mask is given the entire image is used for histogram computation.\n\nImageOps.autocontrast cutoffs\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nPreviously, the ``cutoff`` parameter of :py:func:`.ImageOps.autocontrast` could only\nbe a single number, used as the percent to cut off from the histogram on the low and\nhigh ends.\n\nNow, it can also be a tuple ``(low, high)``.\n\nImageDraw.regular_polygon\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA new method :py:meth:`.ImageDraw.regular_polygon`, draws a regular polygon of ``n_sides``, inscribed in a ``bounding_circle``.\n\nFor example ``draw.regular_polygon(((100, 100), 50), 5)``\ndraws a pentagon centered at the point ``(100, 100)`` with a polygon radius of ``50``.\n\nSecurity\n========\n\nTODO\n\nOther Changes\n=============\n\nTODO\n^^^^\n\nTODO\n",
            "new_file_content": "8.0.0\n-----\n\nBackwards Incompatible Changes\n==============================\n\nPython 3.5\n^^^^^^^^^^\n\nPillow has dropped support for Python 3.5, which reached end-of-life on 2020-09-13.\n\nim.offset\n^^^^^^^^^\n\n``im.offset()`` has been removed, call :py:func:`.ImageChops.offset()` instead.\n\nImage.fromstring, im.fromstring and im.tostring\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n* ``Image.fromstring()`` has been removed, call :py:func:`.Image.frombytes()` instead.\n* ``im.fromstring()`` has been removed, call :py:meth:`~PIL.Image.Image.frombytes()` instead.\n* ``im.tostring()`` has been removed, call :py:meth:`~PIL.Image.Image.tobytes()` instead.\n\nImageCms.CmsProfile attributes\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nSome attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed:\n\n========================  ===================================================\nRemoved                   Use instead\n========================  ===================================================\n``color_space``           Padded :py:attr:`~.CmsProfile.xcolor_space`\n``pcs``                   Padded :py:attr:`~.CmsProfile.connection_space`\n``product_copyright``     Unicode :py:attr:`~.CmsProfile.copyright`\n``product_desc``          Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_description``   Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_manufacturer``  Unicode :py:attr:`~.CmsProfile.manufacturer`\n``product_model``         Unicode :py:attr:`~.CmsProfile.model`\n========================  ===================================================\n\nAPI Changes\n===========\n\nAdd MIME type to PsdImagePlugin\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\"image/vnd.adobe.photoshop\" is now registered as the\n:py:class:`.PsdImagePlugin.PsdImageFile` MIME type.\n\nAPI Additions\n=============\n\nImage.open: add formats parameter\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAdded a new ``formats`` parameter to :py:func:`.Image.open`:\n\n* A list or tuple of formats to attempt to load the file in.\n  This can be used to restrict the set of formats checked.\n  Pass ``None`` to try all supported formats. You can print the set of\n  available formats by running ``python -m PIL`` or using\n  the :py:func:`PIL.features.pilinfo` function.\n\nImageOps.autocontrast: add mask parameter\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n:py:func:`.ImageOps.autocontrast` can now take a ``mask`` parameter:\n\n* Histogram used in contrast operation is computed using pixels within the mask.\n  If no mask is given the entire image is used for histogram computation.\n\nImageOps.autocontrast cutoffs\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nPreviously, the ``cutoff`` parameter of :py:func:`.ImageOps.autocontrast` could only\nbe a single number, used as the percent to cut off from the histogram on the low and\nhigh ends.\n\nNow, it can also be a tuple ``(low, high)``.\n\nImageDraw.regular_polygon\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA new method :py:meth:`.ImageDraw.regular_polygon`, draws a regular polygon of ``n_sides``, inscribed in a ``bounding_circle``.\n\nFor example ``draw.regular_polygon(((100, 100), 50), 5)``\ndraws a pentagon centered at the point ``(100, 100)`` with a polygon radius of ``50``.\n\nOther Changes\n=============\n\nError for large BMP files\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\nPreviously, if a BMP file was too large, an ``OSError`` would be raised. Now,\n``DecompressionBombError`` is used instead, as Pillow already uses for other formats.\n",
            "header": {
                "file": {
                    "path": "docs/releasenotes/8.0.0.rst"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "79fdb7340",
                "new_commit_hash": "4d79b4aaf",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/docs/releasenotes/8.0.0.rst"
            },
            "plus_file": {
                "path": "b/docs/releasenotes/8.0.0.rst"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 86,
                            "length": 15
                        },
                        "new_range": {
                            "start": 86,
                            "length": 11
                        },
                        "section": "A new method :py:meth:`.ImageDraw.regular_polygon`, draws a regular polygon of `"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "For example ``draw.regular_polygon(((100, 100), 50), 5)``",
                                "type": "context"
                            },
                            {
                                "content": "draws a pentagon centered at the point ``(100, 100)`` with a polygon radius of ``50``.",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "Security",
                                "type": "deleted"
                            },
                            {
                                "content": "========",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "TODO",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "Other Changes",
                                "type": "context"
                            },
                            {
                                "content": "=============",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "TODO",
                                "type": "deleted"
                            },
                            {
                                "content": "^^^^",
                                "type": "deleted"
                            },
                            {
                                "content": "Error for large BMP files",
                                "type": "added"
                            },
                            {
                                "content": "^^^^^^^^^^^^^^^^^^^^^^^^^",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "TODO",
                                "type": "deleted"
                            },
                            {
                                "content": "Previously, if a BMP file was too large, an ``OSError`` would be raised. Now,",
                                "type": "added"
                            },
                            {
                                "content": "``DecompressionBombError`` is used instead, as Pillow already uses for other formats.",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# BMP file handler\n#\n# Windows (and OS/2) native bitmap storage format.\n#\n# history:\n# 1995-09-01 fl   Created\n# 1996-04-30 fl   Added save\n# 1997-08-27 fl   Fixed save of 1-bit images\n# 1998-03-06 fl   Load P images as L where possible\n# 1998-07-03 fl   Load P images as 1 where possible\n# 1998-12-29 fl   Handle small palettes\n# 2002-12-30 fl   Fixed load of 1-bit palette images\n# 2003-04-21 fl   Fixed load of 1-bit monochrome images\n# 2003-04-23 fl   Added limited support for BI_BITFIELDS compression\n#\n# Copyright (c) 1997-2003 by Secret Labs AB\n# Copyright (c) 1995-2003 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\n\nfrom . import Image, ImageFile, ImagePalette\nfrom ._binary import i8\nfrom ._binary import i16le as i16\nfrom ._binary import i32le as i32\nfrom ._binary import o8\nfrom ._binary import o16le as o16\nfrom ._binary import o32le as o32\n\n#\n# --------------------------------------------------------------------\n# Read BMP file\n\nBIT2MODE = {\n    # bits => mode, rawmode\n    1: (\"P\", \"P;1\"),\n    4: (\"P\", \"P;4\"),\n    8: (\"P\", \"P\"),\n    16: (\"RGB\", \"BGR;15\"),\n    24: (\"RGB\", \"BGR\"),\n    32: (\"RGB\", \"BGRX\"),\n}\n\n\ndef _accept(prefix):\n    return prefix[:2] == b\"BM\"\n\n\ndef _dib_accept(prefix):\n    return i32(prefix[:4]) in [12, 40, 64, 108, 124]\n\n\n# =============================================================================\n# Image plugin for the Windows BMP format.\n# =============================================================================\nclass BmpImageFile(ImageFile.ImageFile):\n    \"\"\" Image plugin for the Windows Bitmap format (BMP) \"\"\"\n\n    # ------------------------------------------------------------- Description\n    format_description = \"Windows Bitmap\"\n    format = \"BMP\"\n\n    # -------------------------------------------------- BMP Compression values\n    COMPRESSIONS = {\"RAW\": 0, \"RLE8\": 1, \"RLE4\": 2, \"BITFIELDS\": 3, \"JPEG\": 4, \"PNG\": 5}\n    for k, v in COMPRESSIONS.items():\n        vars()[k] = v\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n\n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n\n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n\n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n\n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n\n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n\n        # ------------------------------- Check abnormal values for DOS attacks\n        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:\n            raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)\n\n        # ---------------------- Check bit depth for unusual unsupported values\n        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))\n        if self.mode is None:\n            raise OSError(f\"Unsupported BMP pixel depth ({file_info['bits']})\")\n\n        # ---------------- Process BMP with Bitfields compression (not palette)\n        if file_info[\"compression\"] == self.BITFIELDS:\n            SUPPORTED = {\n                32: [\n                    (0xFF0000, 0xFF00, 0xFF, 0x0),\n                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),\n                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),\n                    (0x0, 0x0, 0x0, 0x0),\n                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),\n                ],\n                24: [(0xFF0000, 0xFF00, 0xFF)],\n                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],\n            }\n            MASK_MODES = {\n                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): \"BGRX\",\n                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): \"XBGR\",\n                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): \"RGBA\",\n                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): \"BGRA\",\n                (32, (0x0, 0x0, 0x0, 0x0)): \"BGRA\",\n                (24, (0xFF0000, 0xFF00, 0xFF)): \"BGR\",\n                (16, (0xF800, 0x7E0, 0x1F)): \"BGR;16\",\n                (16, (0x7C00, 0x3E0, 0x1F)): \"BGR;15\",\n            }\n            if file_info[\"bits\"] in SUPPORTED:\n                if (\n                    file_info[\"bits\"] == 32\n                    and file_info[\"rgba_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgba_mask\"])]\n                    self.mode = \"RGBA\" if \"A\" in raw_mode else self.mode\n                elif (\n                    file_info[\"bits\"] in (24, 16)\n                    and file_info[\"rgb_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgb_mask\"])]\n                else:\n                    raise OSError(\"Unsupported BMP bitfields layout\")\n            else:\n                raise OSError(\"Unsupported BMP bitfields layout\")\n        elif file_info[\"compression\"] == self.RAW:\n            if file_info[\"bits\"] == 32 and header == 22:  # 32-bit .cur offset\n                raw_mode, self.mode = \"BGRA\", \"RGBA\"\n        else:\n            raise OSError(f\"Unsupported BMP compression ({file_info['compression']})\")\n\n        # --------------- Once the header is processed, process the palette/LUT\n        if self.mode == \"P\":  # Paletted for 1, 4 and 8 bit images\n\n            # ---------------------------------------------------- 1-bit images\n            if not (0 < file_info[\"colors\"] <= 65536):\n                raise OSError(f\"Unsupported BMP Palette size ({file_info['colors']})\")\n            else:\n                padding = file_info[\"palette_padding\"]\n                palette = read(padding * file_info[\"colors\"])\n                greyscale = True\n                indices = (\n                    (0, 255)\n                    if file_info[\"colors\"] == 2\n                    else list(range(file_info[\"colors\"]))\n                )\n\n                # ----------------- Check if greyscale and ignore palette if so\n                for ind, val in enumerate(indices):\n                    rgb = palette[ind * padding : ind * padding + 3]\n                    if rgb != o8(val) * 3:\n                        greyscale = False\n\n                # ------- If all colors are grey, white or black, ditch palette\n                if greyscale:\n                    self.mode = \"1\" if file_info[\"colors\"] == 2 else \"L\"\n                    raw_mode = self.mode\n                else:\n                    self.mode = \"P\"\n                    self.palette = ImagePalette.raw(\n                        \"BGRX\" if padding == 4 else \"BGR\", palette\n                    )\n\n        # ---------------------------- Finally set the tile data for the plugin\n        self.info[\"compression\"] = file_info[\"compression\"]\n        self.tile = [\n            (\n                \"raw\",\n                (0, 0, file_info[\"width\"], file_info[\"height\"]),\n                offset or self.fp.tell(),\n                (\n                    raw_mode,\n                    ((file_info[\"width\"] * file_info[\"bits\"] + 31) >> 3) & (~3),\n                    file_info[\"direction\"],\n                ),\n            )\n        ]\n\n    def _open(self):\n        \"\"\" Open file, check magic number and read header \"\"\"\n        # read 14 bytes: magic number, filesize, reserved, header final offset\n        head_data = self.fp.read(14)\n        # choke if the file does not have the required magic bytes\n        if not _accept(head_data):\n            raise SyntaxError(\"Not a BMP file\")\n        # read the start position of the BMP image data (u32)\n        offset = i32(head_data[10:14])\n        # load bitmap information (offset=raster info)\n        self._bitmap(offset=offset)\n\n\n# =============================================================================\n# Image plugin for the DIB format (BMP alias)\n# =============================================================================\nclass DibImageFile(BmpImageFile):\n\n    format = \"DIB\"\n    format_description = \"Windows Bitmap\"\n\n    def _open(self):\n        self._bitmap()\n\n\n#\n# --------------------------------------------------------------------\n# Write BMP file\n\n\nSAVE = {\n    \"1\": (\"1\", 1, 2),\n    \"L\": (\"L\", 8, 256),\n    \"P\": (\"P\", 8, 256),\n    \"RGB\": (\"BGR\", 24, 0),\n    \"RGBA\": (\"BGRA\", 32, 0),\n}\n\n\ndef _dib_save(im, fp, filename):\n    _save(im, fp, filename, False)\n\n\ndef _save(im, fp, filename, bitmap_header=True):\n    try:\n        rawmode, bits, colors = SAVE[im.mode]\n    except KeyError as e:\n        raise OSError(f\"cannot write mode {im.mode} as BMP\") from e\n\n    info = im.encoderinfo\n\n    dpi = info.get(\"dpi\", (96, 96))\n\n    # 1 meter == 39.3701 inches\n    ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))\n\n    stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)\n    header = 40  # or 64 for OS/2 version 2\n    image = stride * im.size[1]\n\n    # bitmap header\n    if bitmap_header:\n        offset = 14 + header + colors * 4\n        file_size = offset + image\n        if file_size > 2 ** 32 - 1:\n            raise ValueError(\"File size is too large for the BMP format\")\n        fp.write(\n            b\"BM\"  # file type (magic)\n            + o32(file_size)  # file size\n            + o32(0)  # reserved\n            + o32(offset)  # image data offset\n        )\n\n    # bitmap info header\n    fp.write(\n        o32(header)  # info header size\n        + o32(im.size[0])  # width\n        + o32(im.size[1])  # height\n        + o16(1)  # planes\n        + o16(bits)  # depth\n        + o32(0)  # compression (0=uncompressed)\n        + o32(image)  # size of bitmap\n        + o32(ppm[0])  # resolution\n        + o32(ppm[1])  # resolution\n        + o32(colors)  # colors used\n        + o32(colors)  # colors important\n    )\n\n    fp.write(b\"\\0\" * (header - 40))  # padding (for OS/2 format)\n\n    if im.mode == \"1\":\n        for i in (0, 255):\n            fp.write(o8(i) * 4)\n    elif im.mode == \"L\":\n        for i in range(256):\n            fp.write(o8(i) * 4)\n    elif im.mode == \"P\":\n        fp.write(im.im.getpalette(\"RGB\", \"BGRX\"))\n\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (rawmode, stride, -1))])\n\n\n#\n# --------------------------------------------------------------------\n# Registry\n\n\nImage.register_open(BmpImageFile.format, BmpImageFile, _accept)\nImage.register_save(BmpImageFile.format, _save)\n\nImage.register_extension(BmpImageFile.format, \".bmp\")\n\nImage.register_mime(BmpImageFile.format, \"image/bmp\")\n\nImage.register_open(DibImageFile.format, DibImageFile, _dib_accept)\nImage.register_save(DibImageFile.format, _dib_save)\n\nImage.register_extension(DibImageFile.format, \".dib\")\n\nImage.register_mime(DibImageFile.format, \"image/bmp\")\n",
            "new_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# BMP file handler\n#\n# Windows (and OS/2) native bitmap storage format.\n#\n# history:\n# 1995-09-01 fl   Created\n# 1996-04-30 fl   Added save\n# 1997-08-27 fl   Fixed save of 1-bit images\n# 1998-03-06 fl   Load P images as L where possible\n# 1998-07-03 fl   Load P images as 1 where possible\n# 1998-12-29 fl   Handle small palettes\n# 2002-12-30 fl   Fixed load of 1-bit palette images\n# 2003-04-21 fl   Fixed load of 1-bit monochrome images\n# 2003-04-23 fl   Added limited support for BI_BITFIELDS compression\n#\n# Copyright (c) 1997-2003 by Secret Labs AB\n# Copyright (c) 1995-2003 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\n\nfrom . import Image, ImageFile, ImagePalette\nfrom ._binary import i8\nfrom ._binary import i16le as i16\nfrom ._binary import i32le as i32\nfrom ._binary import o8\nfrom ._binary import o16le as o16\nfrom ._binary import o32le as o32\n\n#\n# --------------------------------------------------------------------\n# Read BMP file\n\nBIT2MODE = {\n    # bits => mode, rawmode\n    1: (\"P\", \"P;1\"),\n    4: (\"P\", \"P;4\"),\n    8: (\"P\", \"P\"),\n    16: (\"RGB\", \"BGR;15\"),\n    24: (\"RGB\", \"BGR\"),\n    32: (\"RGB\", \"BGRX\"),\n}\n\n\ndef _accept(prefix):\n    return prefix[:2] == b\"BM\"\n\n\ndef _dib_accept(prefix):\n    return i32(prefix[:4]) in [12, 40, 64, 108, 124]\n\n\n# =============================================================================\n# Image plugin for the Windows BMP format.\n# =============================================================================\nclass BmpImageFile(ImageFile.ImageFile):\n    \"\"\" Image plugin for the Windows Bitmap format (BMP) \"\"\"\n\n    # ------------------------------------------------------------- Description\n    format_description = \"Windows Bitmap\"\n    format = \"BMP\"\n\n    # -------------------------------------------------- BMP Compression values\n    COMPRESSIONS = {\"RAW\": 0, \"RLE8\": 1, \"RLE4\": 2, \"BITFIELDS\": 3, \"JPEG\": 4, \"PNG\": 5}\n    for k, v in COMPRESSIONS.items():\n        vars()[k] = v\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n\n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n\n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n\n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n\n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n\n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n\n        # ---------------------- Check bit depth for unusual unsupported values\n        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))\n        if self.mode is None:\n            raise OSError(f\"Unsupported BMP pixel depth ({file_info['bits']})\")\n\n        # ---------------- Process BMP with Bitfields compression (not palette)\n        if file_info[\"compression\"] == self.BITFIELDS:\n            SUPPORTED = {\n                32: [\n                    (0xFF0000, 0xFF00, 0xFF, 0x0),\n                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),\n                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),\n                    (0x0, 0x0, 0x0, 0x0),\n                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),\n                ],\n                24: [(0xFF0000, 0xFF00, 0xFF)],\n                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],\n            }\n            MASK_MODES = {\n                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): \"BGRX\",\n                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): \"XBGR\",\n                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): \"RGBA\",\n                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): \"BGRA\",\n                (32, (0x0, 0x0, 0x0, 0x0)): \"BGRA\",\n                (24, (0xFF0000, 0xFF00, 0xFF)): \"BGR\",\n                (16, (0xF800, 0x7E0, 0x1F)): \"BGR;16\",\n                (16, (0x7C00, 0x3E0, 0x1F)): \"BGR;15\",\n            }\n            if file_info[\"bits\"] in SUPPORTED:\n                if (\n                    file_info[\"bits\"] == 32\n                    and file_info[\"rgba_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgba_mask\"])]\n                    self.mode = \"RGBA\" if \"A\" in raw_mode else self.mode\n                elif (\n                    file_info[\"bits\"] in (24, 16)\n                    and file_info[\"rgb_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgb_mask\"])]\n                else:\n                    raise OSError(\"Unsupported BMP bitfields layout\")\n            else:\n                raise OSError(\"Unsupported BMP bitfields layout\")\n        elif file_info[\"compression\"] == self.RAW:\n            if file_info[\"bits\"] == 32 and header == 22:  # 32-bit .cur offset\n                raw_mode, self.mode = \"BGRA\", \"RGBA\"\n        else:\n            raise OSError(f\"Unsupported BMP compression ({file_info['compression']})\")\n\n        # --------------- Once the header is processed, process the palette/LUT\n        if self.mode == \"P\":  # Paletted for 1, 4 and 8 bit images\n\n            # ---------------------------------------------------- 1-bit images\n            if not (0 < file_info[\"colors\"] <= 65536):\n                raise OSError(f\"Unsupported BMP Palette size ({file_info['colors']})\")\n            else:\n                padding = file_info[\"palette_padding\"]\n                palette = read(padding * file_info[\"colors\"])\n                greyscale = True\n                indices = (\n                    (0, 255)\n                    if file_info[\"colors\"] == 2\n                    else list(range(file_info[\"colors\"]))\n                )\n\n                # ----------------- Check if greyscale and ignore palette if so\n                for ind, val in enumerate(indices):\n                    rgb = palette[ind * padding : ind * padding + 3]\n                    if rgb != o8(val) * 3:\n                        greyscale = False\n\n                # ------- If all colors are grey, white or black, ditch palette\n                if greyscale:\n                    self.mode = \"1\" if file_info[\"colors\"] == 2 else \"L\"\n                    raw_mode = self.mode\n                else:\n                    self.mode = \"P\"\n                    self.palette = ImagePalette.raw(\n                        \"BGRX\" if padding == 4 else \"BGR\", palette\n                    )\n\n        # ---------------------------- Finally set the tile data for the plugin\n        self.info[\"compression\"] = file_info[\"compression\"]\n        self.tile = [\n            (\n                \"raw\",\n                (0, 0, file_info[\"width\"], file_info[\"height\"]),\n                offset or self.fp.tell(),\n                (\n                    raw_mode,\n                    ((file_info[\"width\"] * file_info[\"bits\"] + 31) >> 3) & (~3),\n                    file_info[\"direction\"],\n                ),\n            )\n        ]\n\n    def _open(self):\n        \"\"\" Open file, check magic number and read header \"\"\"\n        # read 14 bytes: magic number, filesize, reserved, header final offset\n        head_data = self.fp.read(14)\n        # choke if the file does not have the required magic bytes\n        if not _accept(head_data):\n            raise SyntaxError(\"Not a BMP file\")\n        # read the start position of the BMP image data (u32)\n        offset = i32(head_data[10:14])\n        # load bitmap information (offset=raster info)\n        self._bitmap(offset=offset)\n\n\n# =============================================================================\n# Image plugin for the DIB format (BMP alias)\n# =============================================================================\nclass DibImageFile(BmpImageFile):\n\n    format = \"DIB\"\n    format_description = \"Windows Bitmap\"\n\n    def _open(self):\n        self._bitmap()\n\n\n#\n# --------------------------------------------------------------------\n# Write BMP file\n\n\nSAVE = {\n    \"1\": (\"1\", 1, 2),\n    \"L\": (\"L\", 8, 256),\n    \"P\": (\"P\", 8, 256),\n    \"RGB\": (\"BGR\", 24, 0),\n    \"RGBA\": (\"BGRA\", 32, 0),\n}\n\n\ndef _dib_save(im, fp, filename):\n    _save(im, fp, filename, False)\n\n\ndef _save(im, fp, filename, bitmap_header=True):\n    try:\n        rawmode, bits, colors = SAVE[im.mode]\n    except KeyError as e:\n        raise OSError(f\"cannot write mode {im.mode} as BMP\") from e\n\n    info = im.encoderinfo\n\n    dpi = info.get(\"dpi\", (96, 96))\n\n    # 1 meter == 39.3701 inches\n    ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))\n\n    stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)\n    header = 40  # or 64 for OS/2 version 2\n    image = stride * im.size[1]\n\n    # bitmap header\n    if bitmap_header:\n        offset = 14 + header + colors * 4\n        file_size = offset + image\n        if file_size > 2 ** 32 - 1:\n            raise ValueError(\"File size is too large for the BMP format\")\n        fp.write(\n            b\"BM\"  # file type (magic)\n            + o32(file_size)  # file size\n            + o32(0)  # reserved\n            + o32(offset)  # image data offset\n        )\n\n    # bitmap info header\n    fp.write(\n        o32(header)  # info header size\n        + o32(im.size[0])  # width\n        + o32(im.size[1])  # height\n        + o16(1)  # planes\n        + o16(bits)  # depth\n        + o32(0)  # compression (0=uncompressed)\n        + o32(image)  # size of bitmap\n        + o32(ppm[0])  # resolution\n        + o32(ppm[1])  # resolution\n        + o32(colors)  # colors used\n        + o32(colors)  # colors important\n    )\n\n    fp.write(b\"\\0\" * (header - 40))  # padding (for OS/2 format)\n\n    if im.mode == \"1\":\n        for i in (0, 255):\n            fp.write(o8(i) * 4)\n    elif im.mode == \"L\":\n        for i in range(256):\n            fp.write(o8(i) * 4)\n    elif im.mode == \"P\":\n        fp.write(im.im.getpalette(\"RGB\", \"BGRX\"))\n\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (rawmode, stride, -1))])\n\n\n#\n# --------------------------------------------------------------------\n# Registry\n\n\nImage.register_open(BmpImageFile.format, BmpImageFile, _accept)\nImage.register_save(BmpImageFile.format, _save)\n\nImage.register_extension(BmpImageFile.format, \".bmp\")\n\nImage.register_mime(BmpImageFile.format, \"image/bmp\")\n\nImage.register_open(DibImageFile.format, DibImageFile, _dib_accept)\nImage.register_save(DibImageFile.format, _dib_save)\n\nImage.register_extension(DibImageFile.format, \".dib\")\n\nImage.register_mime(DibImageFile.format, \"image/bmp\")\n",
            "header": {
                "file": {
                    "path": "src/PIL/BmpImagePlugin.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "711e030e1",
                "new_commit_hash": "1bcbe93b2",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/BmpImagePlugin.py"
            },
            "plus_file": {
                "path": "b/src/PIL/BmpImagePlugin.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 162,
                            "length": 10
                        },
                        "new_range": {
                            "start": 162,
                            "length": 6
                        },
                        "section": "class BmpImageFile(ImageFile.ImageFile):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            else (1 << file_info[\"bits\"])",
                                "type": "context"
                            },
                            {
                                "content": "        )",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # ------------------------------- Check abnormal values for DOS attacks",
                                "type": "deleted"
                            },
                            {
                                "content": "        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:",
                                "type": "deleted"
                            },
                            {
                                "content": "            raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "        # ---------------------- Check bit depth for unusual unsupported values",
                                "type": "context"
                            },
                            {
                                "content": "        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))",
                                "type": "context"
                            },
                            {
                                "content": "        if self.mode is None:",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/BmpImagePlugin.py",
                            "type": "method",
                            "name": "BmpImageFile._bitmap",
                            "content": "class BmpImageFile(ImageFile.ImageFile):\n    \"\"\" Image plugin for the Windows Bitmap format (BMP) \"\"\"\n\n    # ------------------------------------------------------------- Description\n    format_description = \"Windows Bitmap\"\n    format = \"BMP\"\n\n    # -------------------------------------------------- BMP Compression values\n    COMPRESSIONS = {\"RAW\": 0, \"RLE8\": 1, \"RLE4\": 2, \"BITFIELDS\": 3, \"JPEG\": 4, \"PNG\": 5}\n    for k, v in COMPRESSIONS.items():\n        vars()[k] = v\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n\n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n\n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n\n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n\n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n\n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n\n        # ------------------------------- Check abnormal values for DOS attacks\n        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:\n            raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)\n\n        # ---------------------- Check bit depth for unusual unsupported values\n        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))\n        if self.mode is None:\n            raise OSError(f\"Unsupported BMP pixel depth ({file_info['bits']})\")\n\n        # ---------------- Process BMP with Bitfields compression (not palette)\n        if file_info[\"compression\"] == self.BITFIELDS:\n            SUPPORTED = {\n                32: [\n                    (0xFF0000, 0xFF00, 0xFF, 0x0),\n                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),\n                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),\n                    (0x0, 0x0, 0x0, 0x0),\n                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),\n                ],\n                24: [(0xFF0000, 0xFF00, 0xFF)],\n                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],\n            }\n            MASK_MODES = {\n                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): \"BGRX\",\n                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): \"XBGR\",\n                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): \"RGBA\",\n                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): \"BGRA\",\n                (32, (0x0, 0x0, 0x0, 0x0)): \"BGRA\",\n                (24, (0xFF0000, 0xFF00, 0xFF)): \"BGR\",\n                (16, (0xF800, 0x7E0, 0x1F)): \"BGR;16\",\n                (16, (0x7C00, 0x3E0, 0x1F)): \"BGR;15\",\n            }\n            if file_info[\"bits\"] in SUPPORTED:\n                if (\n                    file_info[\"bits\"] == 32\n                    and file_info[\"rgba_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgba_mask\"])]\n                    self.mode = \"RGBA\" if \"A\" in raw_mode else self.mode\n                elif (\n                    file_info[\"bits\"] in (24, 16)\n                    and file_info[\"rgb_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgb_mask\"])]\n                else:\n                    raise OSError(\"Unsupported BMP bitfields layout\")\n            else:\n                raise OSError(\"Unsupported BMP bitfields layout\")\n        elif file_info[\"compression\"] == self.RAW:\n            if file_info[\"bits\"] == 32 and header == 22:  # 32-bit .cur offset\n                raw_mode, self.mode = \"BGRA\", \"RGBA\"\n        else:\n            raise OSError(f\"Unsupported BMP compression ({file_info['compression']})\")\n\n        # --------------- Once the header is processed, process the palette/LUT\n        if self.mode == \"P\":  # Paletted for 1, 4 and 8 bit images\n\n            # ---------------------------------------------------- 1-bit images\n            if not (0 < file_info[\"colors\"] <= 65536):\n                raise OSError(f\"Unsupported BMP Palette size ({file_info['colors']})\")\n            else:\n                padding = file_info[\"palette_padding\"]\n                palette = read(padding * file_info[\"colors\"])\n                greyscale = True\n                indices = (\n                    (0, 255)\n                    if file_info[\"colors\"] == 2\n                    else list(range(file_info[\"colors\"]))\n                )\n\n                # ----------------- Check if greyscale and ignore palette if so\n                for ind, val in enumerate(indices):\n                    rgb = palette[ind * padding : ind * padding + 3]\n                    if rgb != o8(val) * 3:\n                        greyscale = False\n\n                # ------- If all colors are grey, white or black, ditch palette\n                if greyscale:\n                    self.mode = \"1\" if file_info[\"colors\"] == 2 else \"L\"\n                    raw_mode = self.mode\n                else:\n                    self.mode = \"P\"\n                    self.palette = ImagePalette.raw(\n                        \"BGRX\" if padding == 4 else \"BGR\", palette\n                    )\n\n        # ---------------------------- Finally set the tile data for the plugin\n        self.info[\"compression\"] = file_info[\"compression\"]\n        self.tile = [\n            (\n                \"raw\",\n                (0, 0, file_info[\"width\"], file_info[\"height\"]),\n                offset or self.fp.tell(),\n                (\n                    raw_mode,\n                    ((file_info[\"width\"] * file_info[\"bits\"] + 31) >> 3) & (~3),\n                    file_info[\"direction\"],\n                ),\n            )\n        ]\n\n    def _open(self):\n        \"\"\" Open file, check magic number and read header \"\"\"\n        # read 14 bytes: magic number, filesize, reserved, header final offset\n        head_data = self.fp.read(14)\n        # choke if the file does not have the required magic bytes\n        if not _accept(head_data):\n            raise SyntaxError(\"Not a BMP file\")\n        # read the start position of the BMP image data (u32)\n        offset = i32(head_data[10:14])\n        # load bitmap information (offset=raster info)\n        self._bitmap(offset=offset)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 73,
                            "end_lineno": 264,
                            "parent": {
                                "file_name": "src/PIL/BmpImagePlugin.py",
                                "type": "class",
                                "name": "BmpImageFile",
                                "content": "class BmpImageFile(ImageFile.ImageFile):\n    \"\"\" Image plugin for the Windows Bitmap format (BMP) \"\"\"\n\n    # ------------------------------------------------------------- Description\n    format_description = \"Windows Bitmap\"\n    format = \"BMP\"\n\n    # -------------------------------------------------- BMP Compression values\n    COMPRESSIONS = {\"RAW\": 0, \"RLE8\": 1, \"RLE4\": 2, \"BITFIELDS\": 3, \"JPEG\": 4, \"PNG\": 5}\n    for k, v in COMPRESSIONS.items():\n        vars()[k] = v\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n\n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n\n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n\n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n\n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n\n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n\n        # ------------------------------- Check abnormal values for DOS attacks\n        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:\n            raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)\n\n        # ---------------------- Check bit depth for unusual unsupported values\n        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))\n        if self.mode is None:\n            raise OSError(f\"Unsupported BMP pixel depth ({file_info['bits']})\")\n\n        # ---------------- Process BMP with Bitfields compression (not palette)\n        if file_info[\"compression\"] == self.BITFIELDS:\n            SUPPORTED = {\n                32: [\n                    (0xFF0000, 0xFF00, 0xFF, 0x0),\n                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),\n                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),\n                    (0x0, 0x0, 0x0, 0x0),\n                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),\n                ],\n                24: [(0xFF0000, 0xFF00, 0xFF)],\n                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],\n            }\n            MASK_MODES = {\n                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): \"BGRX\",\n                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): \"XBGR\",\n                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): \"RGBA\",\n                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): \"BGRA\",\n                (32, (0x0, 0x0, 0x0, 0x0)): \"BGRA\",\n                (24, (0xFF0000, 0xFF00, 0xFF)): \"BGR\",\n                (16, (0xF800, 0x7E0, 0x1F)): \"BGR;16\",\n                (16, (0x7C00, 0x3E0, 0x1F)): \"BGR;15\",\n            }\n            if file_info[\"bits\"] in SUPPORTED:\n                if (\n                    file_info[\"bits\"] == 32\n                    and file_info[\"rgba_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgba_mask\"])]\n                    self.mode = \"RGBA\" if \"A\" in raw_mode else self.mode\n                elif (\n                    file_info[\"bits\"] in (24, 16)\n                    and file_info[\"rgb_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgb_mask\"])]\n                else:\n                    raise OSError(\"Unsupported BMP bitfields layout\")\n            else:\n                raise OSError(\"Unsupported BMP bitfields layout\")\n        elif file_info[\"compression\"] == self.RAW:\n            if file_info[\"bits\"] == 32 and header == 22:  # 32-bit .cur offset\n                raw_mode, self.mode = \"BGRA\", \"RGBA\"\n        else:\n            raise OSError(f\"Unsupported BMP compression ({file_info['compression']})\")\n\n        # --------------- Once the header is processed, process the palette/LUT\n        if self.mode == \"P\":  # Paletted for 1, 4 and 8 bit images\n\n            # ---------------------------------------------------- 1-bit images\n            if not (0 < file_info[\"colors\"] <= 65536):\n                raise OSError(f\"Unsupported BMP Palette size ({file_info['colors']})\")\n            else:\n                padding = file_info[\"palette_padding\"]\n                palette = read(padding * file_info[\"colors\"])\n                greyscale = True\n                indices = (\n                    (0, 255)\n                    if file_info[\"colors\"] == 2\n                    else list(range(file_info[\"colors\"]))\n                )\n\n                # ----------------- Check if greyscale and ignore palette if so\n                for ind, val in enumerate(indices):\n                    rgb = palette[ind * padding : ind * padding + 3]\n                    if rgb != o8(val) * 3:\n                        greyscale = False\n\n                # ------- If all colors are grey, white or black, ditch palette\n                if greyscale:\n                    self.mode = \"1\" if file_info[\"colors\"] == 2 else \"L\"\n                    raw_mode = self.mode\n                else:\n                    self.mode = \"P\"\n                    self.palette = ImagePalette.raw(\n                        \"BGRX\" if padding == 4 else \"BGR\", palette\n                    )\n\n        # ---------------------------- Finally set the tile data for the plugin\n        self.info[\"compression\"] = file_info[\"compression\"]\n        self.tile = [\n            (\n                \"raw\",\n                (0, 0, file_info[\"width\"], file_info[\"height\"]),\n                offset or self.fp.tell(),\n                (\n                    raw_mode,\n                    ((file_info[\"width\"] * file_info[\"bits\"] + 31) >> 3) & (~3),\n                    file_info[\"direction\"],\n                ),\n            )\n        ]\n\n    def _open(self):\n        \"\"\" Open file, check magic number and read header \"\"\"\n        # read 14 bytes: magic number, filesize, reserved, header final offset\n        head_data = self.fp.read(14)\n        # choke if the file does not have the required magic bytes\n        if not _accept(head_data):\n            raise SyntaxError(\"Not a BMP file\")\n        # read the start position of the BMP image data (u32)\n        offset = i32(head_data[10:14])\n        # load bitmap information (offset=raster info)\n        self._bitmap(offset=offset)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 61,
                                "end_lineno": 276,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "src/PIL/BmpImagePlugin.py",
                            "type": "class",
                            "name": "BmpImageFile",
                            "content": "class BmpImageFile(ImageFile.ImageFile):\n    \"\"\" Image plugin for the Windows Bitmap format (BMP) \"\"\"\n\n    # ------------------------------------------------------------- Description\n    format_description = \"Windows Bitmap\"\n    format = \"BMP\"\n\n    # -------------------------------------------------- BMP Compression values\n    COMPRESSIONS = {\"RAW\": 0, \"RLE8\": 1, \"RLE4\": 2, \"BITFIELDS\": 3, \"JPEG\": 4, \"PNG\": 5}\n    for k, v in COMPRESSIONS.items():\n        vars()[k] = v\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n\n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n\n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n\n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n\n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n\n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n\n        # ------------------------------- Check abnormal values for DOS attacks\n        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:\n            raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)\n\n        # ---------------------- Check bit depth for unusual unsupported values\n        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))\n        if self.mode is None:\n            raise OSError(f\"Unsupported BMP pixel depth ({file_info['bits']})\")\n\n        # ---------------- Process BMP with Bitfields compression (not palette)\n        if file_info[\"compression\"] == self.BITFIELDS:\n            SUPPORTED = {\n                32: [\n                    (0xFF0000, 0xFF00, 0xFF, 0x0),\n                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),\n                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),\n                    (0x0, 0x0, 0x0, 0x0),\n                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),\n                ],\n                24: [(0xFF0000, 0xFF00, 0xFF)],\n                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],\n            }\n            MASK_MODES = {\n                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): \"BGRX\",\n                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): \"XBGR\",\n                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): \"RGBA\",\n                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): \"BGRA\",\n                (32, (0x0, 0x0, 0x0, 0x0)): \"BGRA\",\n                (24, (0xFF0000, 0xFF00, 0xFF)): \"BGR\",\n                (16, (0xF800, 0x7E0, 0x1F)): \"BGR;16\",\n                (16, (0x7C00, 0x3E0, 0x1F)): \"BGR;15\",\n            }\n            if file_info[\"bits\"] in SUPPORTED:\n                if (\n                    file_info[\"bits\"] == 32\n                    and file_info[\"rgba_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgba_mask\"])]\n                    self.mode = \"RGBA\" if \"A\" in raw_mode else self.mode\n                elif (\n                    file_info[\"bits\"] in (24, 16)\n                    and file_info[\"rgb_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgb_mask\"])]\n                else:\n                    raise OSError(\"Unsupported BMP bitfields layout\")\n            else:\n                raise OSError(\"Unsupported BMP bitfields layout\")\n        elif file_info[\"compression\"] == self.RAW:\n            if file_info[\"bits\"] == 32 and header == 22:  # 32-bit .cur offset\n                raw_mode, self.mode = \"BGRA\", \"RGBA\"\n        else:\n            raise OSError(f\"Unsupported BMP compression ({file_info['compression']})\")\n\n        # --------------- Once the header is processed, process the palette/LUT\n        if self.mode == \"P\":  # Paletted for 1, 4 and 8 bit images\n\n            # ---------------------------------------------------- 1-bit images\n            if not (0 < file_info[\"colors\"] <= 65536):\n                raise OSError(f\"Unsupported BMP Palette size ({file_info['colors']})\")\n            else:\n                padding = file_info[\"palette_padding\"]\n                palette = read(padding * file_info[\"colors\"])\n                greyscale = True\n                indices = (\n                    (0, 255)\n                    if file_info[\"colors\"] == 2\n                    else list(range(file_info[\"colors\"]))\n                )\n\n                # ----------------- Check if greyscale and ignore palette if so\n                for ind, val in enumerate(indices):\n                    rgb = palette[ind * padding : ind * padding + 3]\n                    if rgb != o8(val) * 3:\n                        greyscale = False\n\n                # ------- If all colors are grey, white or black, ditch palette\n                if greyscale:\n                    self.mode = \"1\" if file_info[\"colors\"] == 2 else \"L\"\n                    raw_mode = self.mode\n                else:\n                    self.mode = \"P\"\n                    self.palette = ImagePalette.raw(\n                        \"BGRX\" if padding == 4 else \"BGR\", palette\n                    )\n\n        # ---------------------------- Finally set the tile data for the plugin\n        self.info[\"compression\"] = file_info[\"compression\"]\n        self.tile = [\n            (\n                \"raw\",\n                (0, 0, file_info[\"width\"], file_info[\"height\"]),\n                offset or self.fp.tell(),\n                (\n                    raw_mode,\n                    ((file_info[\"width\"] * file_info[\"bits\"] + 31) >> 3) & (~3),\n                    file_info[\"direction\"],\n                ),\n            )\n        ]\n\n    def _open(self):\n        \"\"\" Open file, check magic number and read header \"\"\"\n        # read 14 bytes: magic number, filesize, reserved, header final offset\n        head_data = self.fp.read(14)\n        # choke if the file does not have the required magic bytes\n        if not _accept(head_data):\n            raise SyntaxError(\"Not a BMP file\")\n        # read the start position of the BMP image data (u32)\n        offset = i32(head_data[10:14])\n        # load bitmap information (offset=raster info)\n        self._bitmap(offset=offset)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 61,
                            "end_lineno": 276,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "fee6bafead4683f5a7d2752339165c699ac907df^",
    "new_commit_hash": "fee6bafead4683f5a7d2752339165c699ac907df",
    "commit_message": "Merge pull request #4966 from radarhere/decompression",
    "commit_date": "2020-10-12T12:13:07+03:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "fee6bafead4683f5a7d2752339165c699ac907df",
    "test_file_codes": [
        "import pytest\n\nfrom PIL import Image\n\nfrom .helper import hopper\n\nTEST_FILE = \"Tests/images/hopper.ppm\"\n\nORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS\n\n\nclass TestDecompressionBomb:\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def test_no_warning_small_file(self):\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_no_warning_no_limit(self):\n        # Arrange\n        # Turn limit off\n        Image.MAX_IMAGE_PIXELS = None\n        assert Image.MAX_IMAGE_PIXELS is None\n\n        # Act / Assert\n        # Implicit assert: no warning.\n        # A warning would cause a failure.\n        with Image.open(TEST_FILE):\n            pass\n\n    def test_warning(self):\n        # Set limit to trigger warning on the test file\n        Image.MAX_IMAGE_PIXELS = 128 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1\n\n        def open():\n            with Image.open(TEST_FILE):\n                pass\n\n        pytest.warns(Image.DecompressionBombWarning, open)\n\n    def test_exception(self):\n        # Set limit to trigger exception on the test file\n        Image.MAX_IMAGE_PIXELS = 64 * 128 - 1\n        assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1\n\n        with pytest.raises(Image.DecompressionBombError):\n            with Image.open(TEST_FILE):\n                pass\n\n    def test_exception_ico(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.ico\")\n\n    def test_exception_gif(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/decompression_bomb.gif\")\n\n    def test_exception_bmp(self):\n        with pytest.raises(Image.DecompressionBombError):\n            Image.open(\"Tests/images/bmp/b/reallybig.bmp\")\n\n\nclass TestDecompressionCrop:\n    @classmethod\n    def setup_class(self):\n        width, height = 128, 128\n        Image.MAX_IMAGE_PIXELS = height * width * 4 - 1\n\n    @classmethod\n    def teardown_class(self):\n        Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT\n\n    def testEnlargeCrop(self):\n        # Crops can extend the extents, therefore we should have the\n        # same decompression bomb warnings on them.\n        with hopper() as src:\n            box = (0, 0, src.width * 2, src.height * 2)\n            pytest.warns(Image.DecompressionBombWarning, src.crop, box)\n\n    def test_crop_decompression_checks(self):\n\n        im = Image.new(\"RGB\", (100, 100))\n\n        good_values = ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990))\n\n        warning_values = ((-160, -160, 99, 99), (160, 160, -99, -99))\n\n        error_values = ((-99909, -99990, 99999, 99999), (99909, 99990, -99999, -99999))\n\n        for value in good_values:\n            assert im.crop(value).size == (9, 9)\n\n        for value in warning_values:\n            pytest.warns(Image.DecompressionBombWarning, im.crop, value)\n\n        for value in error_values:\n            with pytest.raises(Image.DecompressionBombError):\n                im.crop(value)\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Pillow installation attempts...\nVerifying Pillow installation...\n✅ Pillow installation successful!\nSuccessfully installed Pillow\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 12 packages in 15ms\nInstalled 12 packages in 277ms\n + coverage==7.6.10\n + exceptiongroup==1.2.2\n + iniconfig==2.0.0\n + packaging==24.2\n + pluggy==1.5.0\n + pyqt5==5.15.11\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.16.1\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + setuptools==75.8.0\n + tomli==2.2.1\nResolved 1 package in 929ms\nPrepared 1 package in 35.76s\nInstalled 1 package in 1ms\n + pillow==8.0.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_fee6bafead4683f5a7d2752339165c699ac907df)\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "\u001b[1m============================= test session starts ==============================\u001b[0m\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_fee6bafead4683f5a7d2752339165c699ac907df\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 9 items\n\nr2e_tests/test_1.py \u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m                                            [100%]\u001b[0m\n\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_no_warning_small_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_no_warning_no_limit\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_warning\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception_ico\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception_gif\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception_bmp\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionCrop::testEnlargeCrop\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionCrop::test_crop_decompression_checks\u001b[0m\n\u001b[32m============================== \u001b[32m\u001b[1m9 passed\u001b[0m\u001b[32m in 0.15s\u001b[0m\u001b[32m ===============================\u001b[0m\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "\u001b[1m============================= test session starts ==============================\u001b[0m\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_fee6bafead4683f5a7d2752339165c699ac907df\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 9 items\n\nr2e_tests/test_1.py \u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31m                                            [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m___________________ TestDecompressionBomb.test_exception_bmp ___________________\u001b[0m\n\nself = <r2e_tests.test_1.TestDecompressionBomb object at 0x70d7b12b43a0>\n\n    def test_exception_bmp(self):\n        with pytest.raises(Image.DecompressionBombError):\n>           Image.open(\"Tests/images/bmp/b/reallybig.bmp\")\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:65: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\u001b[1m\u001b[31msrc/PIL/Image.py\u001b[0m:2929: in open\n    im = _open_core(fp, filename, prefix, formats)\n\u001b[1m\u001b[31msrc/PIL/Image.py\u001b[0m:2915: in _open_core\n    im = factory(fp, filename)\n\u001b[1m\u001b[31msrc/PIL/ImageFile.py\u001b[0m:121: in __init__\n    self._open()\n\u001b[1m\u001b[31msrc/PIL/BmpImagePlugin.py\u001b[0m:276: in _open\n    self._bitmap(offset=offset)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <PIL.BmpImagePlugin.BmpImageFile image mode= size=3000000x2000000 at 0x70D7B114CC10>\nheader = 0, offset = 54\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n    \n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n    \n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n    \n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n    \n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n    \n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n    \n        # ------------------------------- Check abnormal values for DOS attacks\n        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:\n>           raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)\n\u001b[1m\u001b[31mE           OSError: Unsupported BMP Size: (3000000x2000000)\u001b[0m\n\n\u001b[1m\u001b[31msrc/PIL/BmpImagePlugin.py\u001b[0m:167: OSError\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_no_warning_small_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_no_warning_no_limit\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_warning\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception_ico\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception_gif\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionCrop::testEnlargeCrop\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionCrop::test_crop_decompression_checks\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestDecompressionBomb::test_exception_bmp\u001b[0m - OSError: Unsupported BMP Size: (3000000x2000000)\n\u001b[31m========================= \u001b[31m\u001b[1m1 failed\u001b[0m, \u001b[32m8 passed\u001b[0m\u001b[31m in 0.17s\u001b[0m\u001b[31m ==========================\u001b[0m\n",
    "old_commit_res_stderr": ""
}
Tests/test_decompression_bomb.py docs/releasenotes/8.0.0.rst src/PIL/BmpImagePlugin.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]

**Title:** Opening Extremely Large BMP Images Raises OSError Instead of DecompressionBombError

**Description:**
When attempting to open a BMP image with extremely large dimensions, an `OSError` is raised indicating the BMP size is unsupported. This behavior is inconsistent with how other image formats handle potential decompression bombs, where a `DecompressionBombError` is expected.

**Example Code:**
```python
from PIL import Image

# Attempt to open a very large BMP image
Image.open("Tests/images/bmp/b/reallybig.bmp")
```

**Expected Behavior:**
Opening a BMP image with excessively large dimensions should raise a `DecompressionBombError` to signal a potential decompression bomb attack, allowing for proper handling and security measures.

**Actual Behavior:**
An `OSError` is raised with the message:
```
Unsupported BMP Size: (3000000x2000000)
```
This prevents the identification and handling of the image as a decompression bomb.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/BmpImagePlugin.py
#
# The Python Imaging Library.
# $Id$
#
# BMP file handler
#
# Windows (and OS/2) native bitmap storage format.
#
# history:
# 1995-09-01 fl   Created
# 1996-04-30 fl   Added save
# 1997-08-27 fl   Fixed save of 1-bit images
# 1998-03-06 fl   Load P images as L where possible
# 1998-07-03 fl   Load P images as 1 where possible
# 1998-12-29 fl   Handle small palettes
# 2002-12-30 fl   Fixed load of 1-bit palette images
# 2003-04-21 fl   Fixed load of 1-bit monochrome images
# 2003-04-23 fl   Added limited support for BI_BITFIELDS compression
#
# Copyright (c) 1997-2003 by Secret Labs AB
# Copyright (c) 1995-2003 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#


from . import Image, ImageFile, ImagePalette
from ._binary import i8
from ._binary import i16le as i16
from ._binary import i32le as i32
from ._binary import o8
from ._binary import o16le as o16
from ._binary import o32le as o32

#
# --------------------------------------------------------------------
# Read BMP file

BIT2MODE = {
    # bits => mode, rawmode
    1: ("P", "P;1"),
    4: ("P", "P;4"),
    8: ("P", "P"),
    16: ("RGB", "BGR;15"),
    24: ("RGB", "BGR"),
    32: ("RGB", "BGRX"),
}


def _accept(prefix):
    return prefix[:2] == b"BM"


def _dib_accept(prefix):
    return i32(prefix[:4]) in [12, 40, 64, 108, 124]


# =============================================================================
# Image plugin for the Windows BMP format.
# =============================================================================
class BmpImageFile(ImageFile.ImageFile):
    """ Image plugin for the Windows Bitmap format (BMP) """

    # ------------------------------------------------------------- Description
    format_description = "Windows Bitmap"
    format = "BMP"

    # -------------------------------------------------- BMP Compression values
    COMPRESSIONS = {"RAW": 0, "RLE8": 1, "RLE4": 2, "BITFIELDS": 3, "JPEG": 4, "PNG": 5}
    for k, v in COMPRESSIONS.items():
        vars()[k] = v

    def _bitmap(self, header=0, offset=0):
        """ Read relevant info about the BMP """
        read, seek = self.fp.read, self.fp.seek
        if header:
            seek(header)
        file_info = {}
        # read bmp header size @offset 14 (this is part of the header size)
        file_info["header_size"] = i32(read(4))
        file_info["direction"] = -1

        # -------------------- If requested, read header at a specific position
        # read the rest of the bmp header, without its size
        header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4)

        # -------------------------------------------------- IBM OS/2 Bitmap v1
        # ----- This format has different offsets because of width/height types
        if file_info["header_size"] == 12:
            file_info["width"] = i16(header_data[0:2])
            file_info["height"] = i16(header_data[2:4])
            file_info["planes"] = i16(header_data[4:6])
            file_info["bits"] = i16(header_data[6:8])
            file_info["compression"] = self.RAW
            file_info["palette_padding"] = 3

        # --------------------------------------------- Windows Bitmap v2 to v5
        # v3, OS/2 v2, v4, v5
        elif file_info["header_size"] in (40, 64, 108, 124):
            file_info["y_flip"] = i8(header_data[7]) == 0xFF
            file_info["direction"] = 1 if file_info["y_flip"] else -1
            file_info["width"] = i32(header_data[0:4])
            file_info["height"] = (
                i32(header_data[4:8])
                if not file_info["y_flip"]
                else 2 ** 32 - i32(header_data[4:8])
            )
            file_info["planes"] = i16(header_data[8:10])
            file_info["bits"] = i16(header_data[10:12])
            file_info["compression"] = i32(header_data[12:16])
            # byte size of pixel data
            file_info["data_size"] = i32(header_data[16:20])
            file_info["pixels_per_meter"] = (
                i32(header_data[20:24]),
                i32(header_data[24:28]),
            )
            file_info["colors"] = i32(header_data[28:32])
            file_info["palette_padding"] = 4
            self.info["dpi"] = tuple(
                int(x / 39.3701 + 0.5) for x in file_info["pixels_per_meter"]
            )
            if file_info["compression"] == self.BITFIELDS:
                if len(header_data) >= 52:
                    for idx, mask in enumerate(
                        ["r_mask", "g_mask", "b_mask", "a_mask"]
                    ):
                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])
                else:
                    # 40 byte headers only have the three components in the
                    # bitfields masks, ref:
                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
                    # See also
                    # https://github.com/python-pillow/Pillow/issues/1293
                    # There is a 4th component in the RGBQuad, in the alpha
                    # location, but it is listed as a reserved component,
                    # and it is not generally an alpha channel
                    file_info["a_mask"] = 0x0
                    for mask in ["r_mask", "g_mask", "b_mask"]:
                        file_info[mask] = i32(read(4))
                file_info["rgb_mask"] = (
                    file_info["r_mask"],
                    file_info["g_mask"],
                    file_info["b_mask"],
                )
                file_info["rgba_mask"] = (
                    file_info["r_mask"],
                    file_info["g_mask"],
                    file_info["b_mask"],
                    file_info["a_mask"],
                )
        else:
            raise OSError(f"Unsupported BMP header type ({file_info['header_size']})")

        # ------------------ Special case : header is reported 40, which
        # ---------------------- is shorter than real size for bpp >= 16
        self._size = file_info["width"], file_info["height"]

        # ------- If color count was not found in the header, compute from bits
        file_info["colors"] = (
            file_info["colors"]
            if file_info.get("colors", 0)
            else (1 << file_info["bits"])
        )

        # ------------------------------- Check abnormal values for DOS attacks
        if file_info["width"] * file_info["height"] > 2 ** 31:
            raise OSError("Unsupported BMP Size: (%dx%d)" % self.size)

        # ---------------------- Check bit depth for unusual unsupported values
        self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
        if self.mode is None:
            raise OSError(f"Unsupported BMP pixel depth ({file_info['bits']})")

        # ---------------- Process BMP with Bitfields compression (not palette)
        if file_info["compression"] == self.BITFIELDS:
            SUPPORTED = {
                32: [
                    (0xFF0000, 0xFF00, 0xFF, 0x0),
                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),
                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),
                    (0x0, 0x0, 0x0, 0x0),
                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),
                ],
                24: [(0xFF0000, 0xFF00, 0xFF)],
                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],
            }
            MASK_MODES = {
                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX",
                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR",
                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA",
                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA",
                (32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
                (24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
                (16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
                (16, (0x7C00, 0x3E0, 0x1F)): "BGR;15",
            }
            if file_info["bits"] in SUPPORTED:
                if (
                    file_info["bits"] == 32
                    and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
                ):
                    raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
                    self.mode = "RGBA" if "A" in raw_mode else self.mode
                elif (
                    file_info["bits"] in (24, 16)
                    and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
                ):
                    raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
                else:
                    raise OSError("Unsupported BMP bitfields layout")
            else:
                raise OSError("Unsupported BMP bitfields layout")
        elif file_info["compression"] == self.RAW:
            if file_info["bits"] == 32 and header == 22:  # 32-bit .cur offset
                raw_mode, self.mode = "BGRA", "RGBA"
        else:
            raise OSError(f"Unsupported BMP compression ({file_info['compression']})")

        # --------------- Once the header is processed, process the palette/LUT
        if self.mode == "P":  # Paletted for 1, 4 and 8 bit images

            # ---------------------------------------------------- 1-bit images
            if not (0 < file_info["colors"] <= 65536):
                raise OSError(f"Unsupported BMP Palette size ({file_info['colors']})")
            else:
                padding = file_info["palette_padding"]
                palette = read(padding * file_info["colors"])
                greyscale = True
                indices = (
                    (0, 255)
                    if file_info["colors"] == 2
                    else list(range(file_info["colors"]))
                )

                # ----------------- Check if greyscale and ignore palette if so
                for ind, val in enumerate(indices):
                    rgb = palette[ind * padding : ind * padding + 3]
                    if rgb != o8(val) * 3:
                        greyscale = False

                # ------- If all colors are grey, white or black, ditch palette
                if greyscale:
                    self.mode = "1" if file_info["colors"] == 2 else "L"
                    raw_mode = self.mode
                else:
                    self.mode = "P"
                    self.palette = ImagePalette.raw(
                        "BGRX" if padding == 4 else "BGR", palette
                    )

        # ---------------------------- Finally set the tile data for the plugin
        self.info["compression"] = file_info["compression"]
        self.tile = [
            (
                "raw",
                (0, 0, file_info["width"], file_info["height"]),
                offset or self.fp.tell(),
                (
                    raw_mode,
                    ((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3),
                    file_info["direction"],
                ),
            )
        ]

    def _open(self):
        """ Open file, check magic number and read header """
        # read 14 bytes: magic number, filesize, reserved, header final offset
        head_data = self.fp.read(14)
        # choke if the file does not have the required magic bytes
        if not _accept(head_data):
            raise SyntaxError("Not a BMP file")
        # read the start position of the BMP image data (u32)
        offset = i32(head_data[10:14])
        # load bitmap information (offset=raster info)
        self._bitmap(offset=offset)


# =============================================================================
# Image plugin for the DIB format (BMP alias)
# =============================================================================
class DibImageFile(BmpImageFile):

    format = "DIB"
    format_description = "Windows Bitmap"

    def _open(self):
        self._bitmap()


#
# --------------------------------------------------------------------
# Write BMP file


SAVE = {
    "1": ("1", 1, 2),
    "L": ("L", 8, 256),
    "P": ("P", 8, 256),
    "RGB": ("BGR", 24, 0),
    "RGBA": ("BGRA", 32, 0),
}


def _dib_save(im, fp, filename):
    _save(im, fp, filename, False)


def _save(im, fp, filename, bitmap_header=True):
    try:
        rawmode, bits, colors = SAVE[im.mode]
    except KeyError as e:
        raise OSError(f"cannot write mode {im.mode} as BMP") from e

    info = im.encoderinfo

    dpi = info.get("dpi", (96, 96))

    # 1 meter == 39.3701 inches
    ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))

    stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
    header = 40  # or 64 for OS/2 version 2
    image = stride * im.size[1]

    # bitmap header
    if bitmap_header:
        offset = 14 + header + colors * 4
        file_size = offset + image
        if file_size > 2 ** 32 - 1:
            raise ValueError("File size is too large for the BMP format")
        fp.write(
            b"BM"  # file type (magic)
            + o32(file_size)  # file size
            + o32(0)  # reserved
            + o32(offset)  # image data offset
        )

    # bitmap info header
    fp.write(
        o32(header)  # info header size
        + o32(im.size[0])  # width
        + o32(im.size[1])  # height
        + o16(1)  # planes
        + o16(bits)  # depth
        + o32(0)  # compression (0=uncompressed)
        + o32(image)  # size of bitmap
        + o32(ppm[0])  # resolution
        + o32(ppm[1])  # resolution
        + o32(colors)  # colors used
        + o32(colors)  # colors important
    )

    fp.write(b"\0" * (header - 40))  # padding (for OS/2 format)

    if im.mode == "1":
        for i in (0, 255):
            fp.write(o8(i) * 4)
    elif im.mode == "L":
        for i in range(256):
            fp.write(o8(i) * 4)
    elif im.mode == "P":
        fp.write(im.im.getpalette("RGB", "BGRX"))

    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))])


#
# --------------------------------------------------------------------
# Registry


Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
Image.register_save(BmpImageFile.format, _save)

Image.register_extension(BmpImageFile.format, ".bmp")

Image.register_mime(BmpImageFile.format, "image/bmp")

Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
Image.register_save(DibImageFile.format, _dib_save)

Image.register_extension(DibImageFile.format, ".dib")

Image.register_mime(DibImageFile.format, "image/bmp")

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]

**Title:** Opening Extremely Large BMP Images Raises OSError Instead of DecompressionBombError

**Description:**
When attempting to open a BMP image with extremely large dimensions, an `OSError` is raised indicating the BMP size is unsupported. This behavior is inconsistent with how other image formats handle potential decompression bombs, where a `DecompressionBombError` is expected.

**Example Code:**
```python
from PIL import Image

# Attempt to open a very large BMP image
Image.open("Tests/images/bmp/b/reallybig.bmp")
```

**Expected Behavior:**
Opening a BMP image with excessively large dimensions should raise a `DecompressionBombError` to signal a potential decompression bomb attack, allowing for proper handling and security measures.

**Actual Behavior:**
An `OSError` is raised with the message:
```
Unsupported BMP Size: (3000000x2000000)
```
This prevents the identification and handling of the image as a decompression bomb.

[/ISSUE]
{
    "\u001b[1mTestDecompressionBomb.test_no_warning_small_file\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionBomb.test_no_warning_no_limit\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionBomb.test_warning\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionBomb.test_exception\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionBomb.test_exception_ico\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionBomb.test_exception_gif\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionBomb.test_exception_bmp\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionCrop.testEnlargeCrop\u001b[0m": "PASSED",
    "\u001b[1mTestDecompressionCrop.test_crop_decompression_checks\u001b[0m": "PASSED"
}
diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py
index 711e030e1..1bcbe93b2 100644
--- a/src/PIL/BmpImagePlugin.py
+++ b/src/PIL/BmpImagePlugin.py
@@ -162,10 +162,6 @@ class BmpImageFile(ImageFile.ImageFile):
             else (1 << file_info["bits"])
         )
 
-        # ------------------------------- Check abnormal values for DOS attacks
-        if file_info["width"] * file_info["height"] > 2 ** 31:
-            raise OSError("Unsupported BMP Size: (%dx%d)" % self.size)
-
         # ---------------------- Check bit depth for unusual unsupported values
         self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
         if self.mode is None:
 

{"src/PIL/BmpImagePlugin.py": "#\n# The Python Imaging Library.\n# $Id$\n#\n# BMP file handler\n#\n# Windows (and OS/2) native bitmap storage format.\n#\n# history:\n# 1995-09-01 fl   Created\n# 1996-04-30 fl   Added save\n# 1997-08-27 fl   Fixed save of 1-bit images\n# 1998-03-06 fl   Load P images as L where possible\n# 1998-07-03 fl   Load P images as 1 where possible\n# 1998-12-29 fl   Handle small palettes\n# 2002-12-30 fl   Fixed load of 1-bit palette images\n# 2003-04-21 fl   Fixed load of 1-bit monochrome images\n# 2003-04-23 fl   Added limited support for BI_BITFIELDS compression\n#\n# Copyright (c) 1997-2003 by Secret Labs AB\n# Copyright (c) 1995-2003 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\n\nfrom . import Image, ImageFile, ImagePalette\nfrom ._binary import i8\nfrom ._binary import i16le as i16\nfrom ._binary import i32le as i32\nfrom ._binary import o8\nfrom ._binary import o16le as o16\nfrom ._binary import o32le as o32\n\n#\n# --------------------------------------------------------------------\n# Read BMP file\n\nBIT2MODE = {\n    # bits => mode, rawmode\n    1: (\"P\", \"P;1\"),\n    4: (\"P\", \"P;4\"),\n    8: (\"P\", \"P\"),\n    16: (\"RGB\", \"BGR;15\"),\n    24: (\"RGB\", \"BGR\"),\n    32: (\"RGB\", \"BGRX\"),\n}\n\n\ndef _accept(prefix):\n    return prefix[:2] == b\"BM\"\n\n\ndef _dib_accept(prefix):\n    return i32(prefix[:4]) in [12, 40, 64, 108, 124]\n\n\n# =============================================================================\n# Image plugin for the Windows BMP format.\n# =============================================================================\nclass BmpImageFile(ImageFile.ImageFile):\n    \"\"\" Image plugin for the Windows Bitmap format (BMP) \"\"\"\n\n    # ------------------------------------------------------------- Description\n    format_description = \"Windows Bitmap\"\n    format = \"BMP\"\n\n    # -------------------------------------------------- BMP Compression values\n    COMPRESSIONS = {\"RAW\": 0, \"RLE8\": 1, \"RLE4\": 2, \"BITFIELDS\": 3, \"JPEG\": 4, \"PNG\": 5}\n    for k, v in COMPRESSIONS.items():\n        vars()[k] = v\n\n    def _bitmap(self, header=0, offset=0):\n        \"\"\" Read relevant info about the BMP \"\"\"\n        read, seek = self.fp.read, self.fp.seek\n        if header:\n            seek(header)\n        file_info = {}\n        # read bmp header size @offset 14 (this is part of the header size)\n        file_info[\"header_size\"] = i32(read(4))\n        file_info[\"direction\"] = -1\n\n        # -------------------- If requested, read header at a specific position\n        # read the rest of the bmp header, without its size\n        header_data = ImageFile._safe_read(self.fp, file_info[\"header_size\"] - 4)\n\n        # -------------------------------------------------- IBM OS/2 Bitmap v1\n        # ----- This format has different offsets because of width/height types\n        if file_info[\"header_size\"] == 12:\n            file_info[\"width\"] = i16(header_data[0:2])\n            file_info[\"height\"] = i16(header_data[2:4])\n            file_info[\"planes\"] = i16(header_data[4:6])\n            file_info[\"bits\"] = i16(header_data[6:8])\n            file_info[\"compression\"] = self.RAW\n            file_info[\"palette_padding\"] = 3\n\n        # --------------------------------------------- Windows Bitmap v2 to v5\n        # v3, OS/2 v2, v4, v5\n        elif file_info[\"header_size\"] in (40, 64, 108, 124):\n            file_info[\"y_flip\"] = i8(header_data[7]) == 0xFF\n            file_info[\"direction\"] = 1 if file_info[\"y_flip\"] else -1\n            file_info[\"width\"] = i32(header_data[0:4])\n            file_info[\"height\"] = (\n                i32(header_data[4:8])\n                if not file_info[\"y_flip\"]\n                else 2 ** 32 - i32(header_data[4:8])\n            )\n            file_info[\"planes\"] = i16(header_data[8:10])\n            file_info[\"bits\"] = i16(header_data[10:12])\n            file_info[\"compression\"] = i32(header_data[12:16])\n            # byte size of pixel data\n            file_info[\"data_size\"] = i32(header_data[16:20])\n            file_info[\"pixels_per_meter\"] = (\n                i32(header_data[20:24]),\n                i32(header_data[24:28]),\n            )\n            file_info[\"colors\"] = i32(header_data[28:32])\n            file_info[\"palette_padding\"] = 4\n            self.info[\"dpi\"] = tuple(\n                int(x / 39.3701 + 0.5) for x in file_info[\"pixels_per_meter\"]\n            )\n            if file_info[\"compression\"] == self.BITFIELDS:\n                if len(header_data) >= 52:\n                    for idx, mask in enumerate(\n                        [\"r_mask\", \"g_mask\", \"b_mask\", \"a_mask\"]\n                    ):\n                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])\n                else:\n                    # 40 byte headers only have the three components in the\n                    # bitfields masks, ref:\n                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx\n                    # See also\n                    # https://github.com/python-pillow/Pillow/issues/1293\n                    # There is a 4th component in the RGBQuad, in the alpha\n                    # location, but it is listed as a reserved component,\n                    # and it is not generally an alpha channel\n                    file_info[\"a_mask\"] = 0x0\n                    for mask in [\"r_mask\", \"g_mask\", \"b_mask\"]:\n                        file_info[mask] = i32(read(4))\n                file_info[\"rgb_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                )\n                file_info[\"rgba_mask\"] = (\n                    file_info[\"r_mask\"],\n                    file_info[\"g_mask\"],\n                    file_info[\"b_mask\"],\n                    file_info[\"a_mask\"],\n                )\n        else:\n            raise OSError(f\"Unsupported BMP header type ({file_info['header_size']})\")\n\n        # ------------------ Special case : header is reported 40, which\n        # ---------------------- is shorter than real size for bpp >= 16\n        self._size = file_info[\"width\"], file_info[\"height\"]\n\n        # ------- If color count was not found in the header, compute from bits\n        file_info[\"colors\"] = (\n            file_info[\"colors\"]\n            if file_info.get(\"colors\", 0)\n            else (1 << file_info[\"bits\"])\n        )\n\n        # ------------------------------- Check abnormal values for DOS attacks\n        if file_info[\"width\"] * file_info[\"height\"] > 2 ** 31:\n            raise OSError(\"Unsupported BMP Size: (%dx%d)\" % self.size)\n\n        # ---------------------- Check bit depth for unusual unsupported values\n        self.mode, raw_mode = BIT2MODE.get(file_info[\"bits\"], (None, None))\n        if self.mode is None:\n            raise OSError(f\"Unsupported BMP pixel depth ({file_info['bits']})\")\n\n        # ---------------- Process BMP with Bitfields compression (not palette)\n        if file_info[\"compression\"] == self.BITFIELDS:\n            SUPPORTED = {\n                32: [\n                    (0xFF0000, 0xFF00, 0xFF, 0x0),\n                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),\n                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),\n                    (0x0, 0x0, 0x0, 0x0),\n                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),\n                ],\n                24: [(0xFF0000, 0xFF00, 0xFF)],\n                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],\n            }\n            MASK_MODES = {\n                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): \"BGRX\",\n                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): \"XBGR\",\n                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): \"RGBA\",\n                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): \"BGRA\",\n                (32, (0x0, 0x0, 0x0, 0x0)): \"BGRA\",\n                (24, (0xFF0000, 0xFF00, 0xFF)): \"BGR\",\n                (16, (0xF800, 0x7E0, 0x1F)): \"BGR;16\",\n                (16, (0x7C00, 0x3E0, 0x1F)): \"BGR;15\",\n            }\n            if file_info[\"bits\"] in SUPPORTED:\n                if (\n                    file_info[\"bits\"] == 32\n                    and file_info[\"rgba_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgba_mask\"])]\n                    self.mode = \"RGBA\" if \"A\" in raw_mode else self.mode\n                elif (\n                    file_info[\"bits\"] in (24, 16)\n                    and file_info[\"rgb_mask\"] in SUPPORTED[file_info[\"bits\"]]\n                ):\n                    raw_mode = MASK_MODES[(file_info[\"bits\"], file_info[\"rgb_mask\"])]\n                else:\n                    raise OSError(\"Unsupported BMP bitfields layout\")\n            else:\n                raise OSError(\"Unsupported BMP bitfields layout\")\n        elif file_info[\"compression\"] == self.RAW:\n            if file_info[\"bits\"] == 32 and header == 22:  # 32-bit .cur offset\n                raw_mode, self.mode = \"BGRA\", \"RGBA\"\n        else:\n            raise OSError(f\"Unsupported BMP compression ({file_info['compression']})\")\n\n        # --------------- Once the header is processed, process the palette/LUT\n        if self.mode == \"P\":  # Paletted for 1, 4 and 8 bit images\n\n            # ---------------------------------------------------- 1-bit images\n            if not (0 < file_info[\"colors\"] <= 65536):\n                raise OSError(f\"Unsupported BMP Palette size ({file_info['colors']})\")\n            else:\n                padding = file_info[\"palette_padding\"]\n                palette = read(padding * file_info[\"colors\"])\n                greyscale = True\n                indices = (\n                    (0, 255)\n                    if file_info[\"colors\"] == 2\n                    else list(range(file_info[\"colors\"]))\n                )\n\n                # ----------------- Check if greyscale and ignore palette if so\n                for ind, val in enumerate(indices):\n                    rgb = palette[ind * padding : ind * padding + 3]\n                    if rgb != o8(val) * 3:\n                        greyscale = False\n\n                # ------- If all colors are grey, white or black, ditch palette\n                if greyscale:\n                    self.mode = \"1\" if file_info[\"colors\"] == 2 else \"L\"\n                    raw_mode = self.mode\n                else:\n                    self.mode = \"P\"\n                    self.palette = ImagePalette.raw(\n                        \"BGRX\" if padding == 4 else \"BGR\", palette\n                    )\n\n        # ---------------------------- Finally set the tile data for the plugin\n        self.info[\"compression\"] = file_info[\"compression\"]\n        self.tile = [\n            (\n                \"raw\",\n                (0, 0, file_info[\"width\"], file_info[\"height\"]),\n                offset or self.fp.tell(),\n                (\n                    raw_mode,\n                    ((file_info[\"width\"] * file_info[\"bits\"] + 31) >> 3) & (~3),\n                    file_info[\"direction\"],\n                ),\n            )\n        ]\n\n    def _open(self):\n        \"\"\" Open file, check magic number and read header \"\"\"\n        # read 14 bytes: magic number, filesize, reserved, header final offset\n        head_data = self.fp.read(14)\n        # choke if the file does not have the required magic bytes\n        if not _accept(head_data):\n            raise SyntaxError(\"Not a BMP file\")\n        # read the start position of the BMP image data (u32)\n        offset = i32(head_data[10:14])\n        # load bitmap information (offset=raster info)\n        self._bitmap(offset=offset)\n\n\n# =============================================================================\n# Image plugin for the DIB format (BMP alias)\n# =============================================================================\nclass DibImageFile(BmpImageFile):\n\n    format = \"DIB\"\n    format_description = \"Windows Bitmap\"\n\n    def _open(self):\n        self._bitmap()\n\n\n#\n# --------------------------------------------------------------------\n# Write BMP file\n\n\nSAVE = {\n    \"1\": (\"1\", 1, 2),\n    \"L\": (\"L\", 8, 256),\n    \"P\": (\"P\", 8, 256),\n    \"RGB\": (\"BGR\", 24, 0),\n    \"RGBA\": (\"BGRA\", 32, 0),\n}\n\n\ndef _dib_save(im, fp, filename):\n    _save(im, fp, filename, False)\n\n\ndef _save(im, fp, filename, bitmap_header=True):\n    try:\n        rawmode, bits, colors = SAVE[im.mode]\n    except KeyError as e:\n        raise OSError(f\"cannot write mode {im.mode} as BMP\") from e\n\n    info = im.encoderinfo\n\n    dpi = info.get(\"dpi\", (96, 96))\n\n    # 1 meter == 39.3701 inches\n    ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))\n\n    stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)\n    header = 40  # or 64 for OS/2 version 2\n    image = stride * im.size[1]\n\n    # bitmap header\n    if bitmap_header:\n        offset = 14 + header + colors * 4\n        file_size = offset + image\n        if file_size > 2 ** 32 - 1:\n            raise ValueError(\"File size is too large for the BMP format\")\n        fp.write(\n            b\"BM\"  # file type (magic)\n            + o32(file_size)  # file size\n            + o32(0)  # reserved\n            + o32(offset)  # image data offset\n        )\n\n    # bitmap info header\n    fp.write(\n        o32(header)  # info header size\n        + o32(im.size[0])  # width\n        + o32(im.size[1])  # height\n        + o16(1)  # planes\n        + o16(bits)  # depth\n        + o32(0)  # compression (0=uncompressed)\n        + o32(image)  # size of bitmap\n        + o32(ppm[0])  # resolution\n        + o32(ppm[1])  # resolution\n        + o32(colors)  # colors used\n        + o32(colors)  # colors important\n    )\n\n    fp.write(b\"\\0\" * (header - 40))  # padding (for OS/2 format)\n\n    if im.mode == \"1\":\n        for i in (0, 255):\n            fp.write(o8(i) * 4)\n    elif im.mode == \"L\":\n        for i in range(256):\n            fp.write(o8(i) * 4)\n    elif im.mode == \"P\":\n        fp.write(im.im.getpalette(\"RGB\", \"BGRX\"))\n\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (rawmode, stride, -1))])\n\n\n#\n# --------------------------------------------------------------------\n# Registry\n\n\nImage.register_open(BmpImageFile.format, BmpImageFile, _accept)\nImage.register_save(BmpImageFile.format, _save)\n\nImage.register_extension(BmpImageFile.format, \".bmp\")\n\nImage.register_mime(BmpImageFile.format, \"image/bmp\")\n\nImage.register_open(DibImageFile.format, DibImageFile, _dib_accept)\nImage.register_save(DibImageFile.format, _dib_save)\n\nImage.register_extension(DibImageFile.format, \".dib\")\n\nImage.register_mime(DibImageFile.format, \"image/bmp\")\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]

**Title:** Opening Extremely Large BMP Images Raises OSError Instead of DecompressionBombError

**Description:**
When attempting to open a BMP image with extremely large dimensions, an `OSError` is raised indicating the BMP size is unsupported. This behavior is inconsistent with how other image formats handle potential decompression bombs, where a `DecompressionBombError` is expected.

**Example Code:**
```python
from PIL import Image

# Attempt to open a very large BMP image
Image.open("Tests/images/bmp/b/reallybig.bmp")
```

**Expected Behavior:**
Opening a BMP image with excessively large dimensions should raise a `DecompressionBombError` to signal a potential decompression bomb attack, allowing for proper handling and security measures.

**Actual Behavior:**
An `OSError` is raised with the message:
```
Unsupported BMP Size: (3000000x2000000)
```
This prevents the identification and handling of the image as a decompression bomb.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/BmpImagePlugin.py
#
# The Python Imaging Library.
# $Id$
#
# BMP file handler
#
# Windows (and OS/2) native bitmap storage format.
#
# history:
# 1995-09-01 fl   Created
# 1996-04-30 fl   Added save
# 1997-08-27 fl   Fixed save of 1-bit images
# 1998-03-06 fl   Load P images as L where possible
# 1998-07-03 fl   Load P images as 1 where possible
# 1998-12-29 fl   Handle small palettes
# 2002-12-30 fl   Fixed load of 1-bit palette images
# 2003-04-21 fl   Fixed load of 1-bit monochrome images
# 2003-04-23 fl   Added limited support for BI_BITFIELDS compression
#
# Copyright (c) 1997-2003 by Secret Labs AB
# Copyright (c) 1995-2003 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#


from . import Image, ImageFile, ImagePalette
from ._binary import i8
from ._binary import i16le as i16
from ._binary import i32le as i32
from ._binary import o8
from ._binary import o16le as o16
from ._binary import o32le as o32

#
# --------------------------------------------------------------------
# Read BMP file

BIT2MODE = {
    # bits => mode, rawmode
    1: ("P", "P;1"),
    4: ("P", "P;4"),
    8: ("P", "P"),
    16: ("RGB", "BGR;15"),
    24: ("RGB", "BGR"),
    32: ("RGB", "BGRX"),
}


def _accept(prefix):
    return prefix[:2] == b"BM"


def _dib_accept(prefix):
    return i32(prefix[:4]) in [12, 40, 64, 108, 124]


# =============================================================================
# Image plugin for the Windows BMP format.
# =============================================================================
class BmpImageFile(ImageFile.ImageFile):
    """ Image plugin for the Windows Bitmap format (BMP) """

    # ------------------------------------------------------------- Description
    format_description = "Windows Bitmap"
    format = "BMP"

    # -------------------------------------------------- BMP Compression values
    COMPRESSIONS = {"RAW": 0, "RLE8": 1, "RLE4": 2, "BITFIELDS": 3, "JPEG": 4, "PNG": 5}
    for k, v in COMPRESSIONS.items():
        vars()[k] = v

    def _bitmap(self, header=0, offset=0):
        """ Read relevant info about the BMP """
        read, seek = self.fp.read, self.fp.seek
        if header:
            seek(header)
        file_info = {}
        # read bmp header size @offset 14 (this is part of the header size)
        file_info["header_size"] = i32(read(4))
        file_info["direction"] = -1

        # -------------------- If requested, read header at a specific position
        # read the rest of the bmp header, without its size
        header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4)

        # -------------------------------------------------- IBM OS/2 Bitmap v1
        # ----- This format has different offsets because of width/height types
        if file_info["header_size"] == 12:
            file_info["width"] = i16(header_data[0:2])
            file_info["height"] = i16(header_data[2:4])
            file_info["planes"] = i16(header_data[4:6])
            file_info["bits"] = i16(header_data[6:8])
            file_info["compression"] = self.RAW
            file_info["palette_padding"] = 3

        # --------------------------------------------- Windows Bitmap v2 to v5
        # v3, OS/2 v2, v4, v5
        elif file_info["header_size"] in (40, 64, 108, 124):
            file_info["y_flip"] = i8(header_data[7]) == 0xFF
            file_info["direction"] = 1 if file_info["y_flip"] else -1
            file_info["width"] = i32(header_data[0:4])
            file_info["height"] = (
                i32(header_data[4:8])
                if not file_info["y_flip"]
                else 2 ** 32 - i32(header_data[4:8])
            )
            file_info["planes"] = i16(header_data[8:10])
            file_info["bits"] = i16(header_data[10:12])
            file_info["compression"] = i32(header_data[12:16])
            # byte size of pixel data
            file_info["data_size"] = i32(header_data[16:20])
            file_info["pixels_per_meter"] = (
                i32(header_data[20:24]),
                i32(header_data[24:28]),
            )
            file_info["colors"] = i32(header_data[28:32])
            file_info["palette_padding"] = 4
            self.info["dpi"] = tuple(
                int(x / 39.3701 + 0.5) for x in file_info["pixels_per_meter"]
            )
            if file_info["compression"] == self.BITFIELDS:
                if len(header_data) >= 52:
                    for idx, mask in enumerate(
                        ["r_mask", "g_mask", "b_mask", "a_mask"]
                    ):
                        file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4])
                else:
                    # 40 byte headers only have the three components in the
                    # bitfields masks, ref:
                    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
                    # See also
                    # https://github.com/python-pillow/Pillow/issues/1293
                    # There is a 4th component in the RGBQuad, in the alpha
                    # location, but it is listed as a reserved component,
                    # and it is not generally an alpha channel
                    file_info["a_mask"] = 0x0
                    for mask in ["r_mask", "g_mask", "b_mask"]:
                        file_info[mask] = i32(read(4))
                file_info["rgb_mask"] = (
                    file_info["r_mask"],
                    file_info["g_mask"],
                    file_info["b_mask"],
                )
                file_info["rgba_mask"] = (
                    file_info["r_mask"],
                    file_info["g_mask"],
                    file_info["b_mask"],
                    file_info["a_mask"],
                )
        else:
            raise OSError(f"Unsupported BMP header type ({file_info['header_size']})")

        # ------------------ Special case : header is reported 40, which
        # ---------------------- is shorter than real size for bpp >= 16
        self._size = file_info["width"], file_info["height"]

        # ------- If color count was not found in the header, compute from bits
        file_info["colors"] = (
            file_info["colors"]
            if file_info.get("colors", 0)
            else (1 << file_info["bits"])
        )

        # ------------------------------- Check abnormal values for DOS attacks
        if file_info["width"] * file_info["height"] > 2 ** 31:
            raise OSError("Unsupported BMP Size: (%dx%d)" % self.size)

        # ---------------------- Check bit depth for unusual unsupported values
        self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
        if self.mode is None:
            raise OSError(f"Unsupported BMP pixel depth ({file_info['bits']})")

        # ---------------- Process BMP with Bitfields compression (not palette)
        if file_info["compression"] == self.BITFIELDS:
            SUPPORTED = {
                32: [
                    (0xFF0000, 0xFF00, 0xFF, 0x0),
                    (0xFF0000, 0xFF00, 0xFF, 0xFF000000),
                    (0xFF, 0xFF00, 0xFF0000, 0xFF000000),
                    (0x0, 0x0, 0x0, 0x0),
                    (0xFF000000, 0xFF0000, 0xFF00, 0x0),
                ],
                24: [(0xFF0000, 0xFF00, 0xFF)],
                16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],
            }
            MASK_MODES = {
                (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX",
                (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR",
                (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA",
                (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA",
                (32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
                (24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
                (16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
                (16, (0x7C00, 0x3E0, 0x1F)): "BGR;15",
            }
            if file_info["bits"] in SUPPORTED:
                if (
                    file_info["bits"] == 32
                    and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
                ):
                    raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
                    self.mode = "RGBA" if "A" in raw_mode else self.mode
                elif (
                    file_info["bits"] in (24, 16)
                    and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
                ):
                    raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
                else:
                    raise OSError("Unsupported BMP bitfields layout")
            else:
                raise OSError("Unsupported BMP bitfields layout")
        elif file_info["compression"] == self.RAW:
            if file_info["bits"] == 32 and header == 22:  # 32-bit .cur offset
                raw_mode, self.mode = "BGRA", "RGBA"
        else:
            raise OSError(f"Unsupported BMP compression ({file_info['compression']})")

        # --------------- Once the header is processed, process the palette/LUT
        if self.mode == "P":  # Paletted for 1, 4 and 8 bit images

            # ---------------------------------------------------- 1-bit images
            if not (0 < file_info["colors"] <= 65536):
                raise OSError(f"Unsupported BMP Palette size ({file_info['colors']})")
            else:
                padding = file_info["palette_padding"]
                palette = read(padding * file_info["colors"])
                greyscale = True
                indices = (
                    (0, 255)
                    if file_info["colors"] == 2
                    else list(range(file_info["colors"]))
                )

                # ----------------- Check if greyscale and ignore palette if so
                for ind, val in enumerate(indices):
                    rgb = palette[ind * padding : ind * padding + 3]
                    if rgb != o8(val) * 3:
                        greyscale = False

                # ------- If all colors are grey, white or black, ditch palette
                if greyscale:
                    self.mode = "1" if file_info["colors"] == 2 else "L"
                    raw_mode = self.mode
                else:
                    self.mode = "P"
                    self.palette = ImagePalette.raw(
                        "BGRX" if padding == 4 else "BGR", palette
                    )

        # ---------------------------- Finally set the tile data for the plugin
        self.info["compression"] = file_info["compression"]
        self.tile = [
            (
                "raw",
                (0, 0, file_info["width"], file_info["height"]),
                offset or self.fp.tell(),
                (
                    raw_mode,
                    ((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3),
                    file_info["direction"],
                ),
            )
        ]

    def _open(self):
        """ Open file, check magic number and read header """
        # read 14 bytes: magic number, filesize, reserved, header final offset
        head_data = self.fp.read(14)
        # choke if the file does not have the required magic bytes
        if not _accept(head_data):
            raise SyntaxError("Not a BMP file")
        # read the start position of the BMP image data (u32)
        offset = i32(head_data[10:14])
        # load bitmap information (offset=raster info)
        self._bitmap(offset=offset)


# =============================================================================
# Image plugin for the DIB format (BMP alias)
# =============================================================================
class DibImageFile(BmpImageFile):

    format = "DIB"
    format_description = "Windows Bitmap"

    def _open(self):
        self._bitmap()


#
# --------------------------------------------------------------------
# Write BMP file


SAVE = {
    "1": ("1", 1, 2),
    "L": ("L", 8, 256),
    "P": ("P", 8, 256),
    "RGB": ("BGR", 24, 0),
    "RGBA": ("BGRA", 32, 0),
}


def _dib_save(im, fp, filename):
    _save(im, fp, filename, False)


def _save(im, fp, filename, bitmap_header=True):
    try:
        rawmode, bits, colors = SAVE[im.mode]
    except KeyError as e:
        raise OSError(f"cannot write mode {im.mode} as BMP") from e

    info = im.encoderinfo

    dpi = info.get("dpi", (96, 96))

    # 1 meter == 39.3701 inches
    ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))

    stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
    header = 40  # or 64 for OS/2 version 2
    image = stride * im.size[1]

    # bitmap header
    if bitmap_header:
        offset = 14 + header + colors * 4
        file_size = offset + image
        if file_size > 2 ** 32 - 1:
            raise ValueError("File size is too large for the BMP format")
        fp.write(
            b"BM"  # file type (magic)
            + o32(file_size)  # file size
            + o32(0)  # reserved
            + o32(offset)  # image data offset
        )

    # bitmap info header
    fp.write(
        o32(header)  # info header size
        + o32(im.size[0])  # width
        + o32(im.size[1])  # height
        + o16(1)  # planes
        + o16(bits)  # depth
        + o32(0)  # compression (0=uncompressed)
        + o32(image)  # size of bitmap
        + o32(ppm[0])  # resolution
        + o32(ppm[1])  # resolution
        + o32(colors)  # colors used
        + o32(colors)  # colors important
    )

    fp.write(b"\0" * (header - 40))  # padding (for OS/2 format)

    if im.mode == "1":
        for i in (0, 255):
            fp.write(o8(i) * 4)
    elif im.mode == "L":
        for i in range(256):
            fp.write(o8(i) * 4)
    elif im.mode == "P":
        fp.write(im.im.getpalette("RGB", "BGRX"))

    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))])


#
# --------------------------------------------------------------------
# Registry


Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
Image.register_save(BmpImageFile.format, _save)

Image.register_extension(BmpImageFile.format, ".bmp")

Image.register_mime(BmpImageFile.format, "image/bmp")

Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
Image.register_save(DibImageFile.format, _dib_save)

Image.register_extension(DibImageFile.format, ".dib")

Image.register_mime(DibImageFile.format, "image/bmp")

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user