From 93b45549611f30169017f6d13e4fed7efa5d8901 Mon Sep 17 00:00:00 2001 From: elasota Date: Sat, 18 Jan 2020 21:15:07 -0500 Subject: [PATCH] Migrate image storage from PICT to BMP --- GpApp/About.cpp | 4 +- GpApp/DialogUtils.cpp | 2 +- GpApp/Map.cpp | 4 +- GpApp/ObjectDraw2.cpp | 26 +- GpApp/ObjectEdit.cpp | 5 +- GpApp/ObjectRects.cpp | 6 +- GpApp/Room.cpp | 11 +- GpApp/RoomGraphics.cpp | 7 +- GpApp/RoomInfo.cpp | 4 +- GpApp/StructuresInit.cpp | 13 +- GpApp/Utilities.cpp | 9 +- PortabilityLayer/BMPFormat.h | 8 +- PortabilityLayer/BitmapImage.cpp | 12 + PortabilityLayer/BitmapImage.h | 11 + PortabilityLayer/PLImageWidget.cpp | 2 +- PortabilityLayer/PLImageWidget.h | 4 +- PortabilityLayer/PLQDOffscreen.cpp | 4 +- PortabilityLayer/PLQDOffscreen.h | 2 +- PortabilityLayer/PLQDraw.cpp | 467 +++++++++--------- PortabilityLayer/PLResourceManager.cpp | 58 ++- PortabilityLayer/PortabilityLayer.vcxproj | 2 + .../PortabilityLayer.vcxproj.filters | 6 + PortabilityLayer/QDGraf.h | 6 +- PortabilityLayer/QDPictHeader.cpp | 19 +- PortabilityLayer/QDStandardPalette.cpp | 4 +- PortabilityLayer/SharedTypes.h | 9 +- PortabilityLayer/ZipFileProxy.cpp | 35 +- gpr2gpa/gpr2gpa.cpp | 42 +- 28 files changed, 438 insertions(+), 344 deletions(-) create mode 100644 PortabilityLayer/BitmapImage.cpp create mode 100644 PortabilityLayer/BitmapImage.h diff --git a/GpApp/About.cpp b/GpApp/About.cpp index 367aaa9..8742e5f 100644 --- a/GpApp/About.cpp +++ b/GpApp/About.cpp @@ -97,7 +97,7 @@ void DoAbout (void) static void HiLiteOkayButton (DrawSurface *surface) { #define kOkayButtPICTHiLit 151 // res ID of unhilit button PICT - THandle thePict; + THandle thePict; if (!okayButtIsHiLit) { @@ -119,7 +119,7 @@ static void HiLiteOkayButton (DrawSurface *surface) static void UnHiLiteOkayButton (DrawSurface *surface) { #define kOkayButtPICTNotHiLit 150 // res ID of hilit button PICT - THandle thePict; + THandle thePict; if (okayButtIsHiLit) { diff --git a/GpApp/DialogUtils.cpp b/GpApp/DialogUtils.cpp index 6937f64..ddaae46 100644 --- a/GpApp/DialogUtils.cpp +++ b/GpApp/DialogUtils.cpp @@ -679,7 +679,7 @@ void DrawDialogUserText2 (Dialog *dial, short item, StringPtr text) void LoadDialogPICT (Dialog *theDialog, short item, short theID) { - THandle thePict; + THandle thePict; Rect iRect = theDialog->GetItems()[item - 1].GetWidget()->GetRect();; diff --git a/GpApp/Map.cpp b/GpApp/Map.cpp index 7cfb8f3..48fc7b6 100644 --- a/GpApp/Map.cpp +++ b/GpApp/Map.cpp @@ -165,12 +165,12 @@ void FindNewActiveRoomRect (void) void LoadGraphicPlus (DrawSurface *surface, short resID, const Rect &theRect) { - THandle thePicture; + THandle thePicture; thePicture = GetPicture(resID); if (thePicture == nil) { - thePicture = GetResource('Date', resID).StaticCast(); + thePicture = GetResource('Date', resID).StaticCast(); if (thePicture == nil) { return; diff --git a/GpApp/ObjectDraw2.cpp b/GpApp/ObjectDraw2.cpp index 9bee33e..8a57e1a 100644 --- a/GpApp/ObjectDraw2.cpp +++ b/GpApp/ObjectDraw2.cpp @@ -5,7 +5,7 @@ //---------------------------------------------------------------------------- //============================================================================ - +#include "BitmapImage.h" #include "PLResources.h" #include "PLTextUtils.h" #include "PLPasStr.h" @@ -1043,11 +1043,11 @@ void DrawWallWindow (Rect *window) void DrawCalendar (Rect *theRect) { - DateTimeRec timeRec; - Rect bounds; - THandle thePicture; - Str255 monthStr; - DrawSurface *wasCPort; + DateTimeRec timeRec; + Rect bounds; + THandle thePicture; + Str255 monthStr; + DrawSurface *wasCPort; wasCPort = GetGraphicsPort(); SetGraphicsPort(backSrcMap); @@ -1056,7 +1056,7 @@ void DrawCalendar (Rect *theRect) if (thePicture == nil) RedAlert(kErrFailedGraphicLoad); - bounds = (*thePicture)->picFrame.ToRect(); + bounds = (*thePicture)->GetRect(); QOffsetRect(&bounds, -bounds.left, -bounds.top); QOffsetRect(&bounds, theRect->left, theRect->top); backSrcMap->DrawPicture(thePicture, bounds); @@ -1075,14 +1075,14 @@ void DrawCalendar (Rect *theRect) void DrawBulletin (Rect *theRect) { - Rect bounds; - THandle thePicture; + Rect bounds; + THandle thePicture; thePicture = GetPicture(kBulletinPictID); if (thePicture == nil) RedAlert(kErrFailedGraphicLoad); - bounds = (*thePicture)->picFrame.ToRect(); + bounds = (*thePicture)->GetRect(); QOffsetRect(&bounds, -bounds.left, -bounds.top); QOffsetRect(&bounds, theRect->left, theRect->top); backSrcMap->DrawPicture(thePicture, bounds); @@ -1093,9 +1093,9 @@ void DrawBulletin (Rect *theRect) void DrawPictObject (short what, Rect *theRect) { - Rect bounds; - THandle thePicture; - short pictID; + Rect bounds; + THandle thePicture; + short pictID; switch (what) { diff --git a/GpApp/ObjectEdit.cpp b/GpApp/ObjectEdit.cpp index 27e0130..3aec11d 100644 --- a/GpApp/ObjectEdit.cpp +++ b/GpApp/ObjectEdit.cpp @@ -8,6 +8,7 @@ #include "PLSound.h" #include "PLToolUtils.h" #include "PLPasStr.h" +#include "BitmapImage.h" #include "Externs.h" #include "House.h" #include "InputManager.h" @@ -2005,7 +2006,7 @@ void SelectPrevObject (void) #ifndef COMPILEDEMO void GetThisRoomsObjRects (void) { - THandle thePict; + THandle thePict; short i, wide, tall; isFirstRoom = (GetFirstRoomNumber() == thisRoomNumber); @@ -2244,7 +2245,7 @@ void GetThisRoomsObjRects (void) } else { - roomObjectRects[i] = (*thePict)->picFrame.ToRect(); + roomObjectRects[i] = (*thePict)->GetRect(); } ZeroRectCorner(&roomObjectRects[i]); QOffsetRect(&roomObjectRects[i], diff --git a/GpApp/ObjectRects.cpp b/GpApp/ObjectRects.cpp index ecd3c7c..316fc1b 100644 --- a/GpApp/ObjectRects.cpp +++ b/GpApp/ObjectRects.cpp @@ -5,7 +5,7 @@ //---------------------------------------------------------------------------- //============================================================================ - +#include "BitmapImage.h" #include "Externs.h" #include "RectUtils.h" @@ -31,7 +31,7 @@ extern short nHotSpots, numChimes; void GetObjectRect (objectPtr who, Rect *itsRect) { - THandle thePict; + THandle thePict; short wide, tall; switch (who->what) @@ -226,7 +226,7 @@ void GetObjectRect (objectPtr who, Rect *itsRect) } else { - *itsRect = (*thePict)->picFrame.ToRect(); + *itsRect = (*thePict)->GetRect(); } ZeroRectCorner(itsRect); QOffsetRect(itsRect, diff --git a/GpApp/Room.cpp b/GpApp/Room.cpp index 02b4194..18c3dc9 100644 --- a/GpApp/Room.cpp +++ b/GpApp/Room.cpp @@ -9,6 +9,7 @@ #include "PLToolUtils.h" #include "PLPasStr.h" #include "PLStandardColors.h" +#include "BitmapImage.h" #include "Externs.h" #include "FontFamily.h" #include "House.h" @@ -237,9 +238,9 @@ Boolean CreateNewRoom (short h, short v) void ReadyBackground (short theID, short *theTiles) { - Rect src, dest; - THandle thePicture; - short i; + Rect src, dest; + THandle thePicture; + short i; if ((noRoomAtAll) || (!houseUnlocked)) { @@ -263,7 +264,7 @@ void ReadyBackground (short theID, short *theTiles) thePicture = GetPicture(theID); if (thePicture == nil) { - thePicture = GetResource('Date', theID).StaticCast(); + thePicture = GetResource('Date', theID).StaticCast(); if (thePicture == nil) { YellowAlert(kYellowNoBackground, 0); @@ -271,7 +272,7 @@ void ReadyBackground (short theID, short *theTiles) } } - dest = (*thePicture)->picFrame.ToRect(); + dest = (*thePicture)->GetRect(); QOffsetRect(&dest, -dest.left, -dest.top); workSrcMap->DrawPicture(thePicture, dest); thePicture.Dispose(); diff --git a/GpApp/RoomGraphics.cpp b/GpApp/RoomGraphics.cpp index 1616380..f1b0f3c 100644 --- a/GpApp/RoomGraphics.cpp +++ b/GpApp/RoomGraphics.cpp @@ -12,6 +12,7 @@ #include "MainWindow.h" #include "RectUtils.h" #include "Room.h" +#include "BitmapImage.h" #define kManholeThruFloor 3957 @@ -131,12 +132,12 @@ void DrawLocale (void) void LoadGraphicSpecial (DrawSurface *surface, short resID) { Rect bounds; - THandle thePicture; + THandle thePicture; thePicture = GetPicture(resID); if (thePicture == nil) { - thePicture = GetResource('Date', resID).StaticCast(); + thePicture = GetResource('Date', resID).StaticCast(); if (thePicture == nil) { thePicture = GetPicture(2000); @@ -145,7 +146,7 @@ void LoadGraphicSpecial (DrawSurface *surface, short resID) } } - bounds = (*thePicture)->picFrame.ToRect(); + bounds = (*thePicture)->GetRect(); OffsetRect(&bounds, -bounds.left, -bounds.top); surface->DrawPicture(thePicture, bounds); diff --git a/GpApp/RoomInfo.cpp b/GpApp/RoomInfo.cpp index 30f65f8..0561d1c 100644 --- a/GpApp/RoomInfo.cpp +++ b/GpApp/RoomInfo.cpp @@ -857,7 +857,7 @@ short ChooseOriginalArt (short was) Boolean PictIDExists (short theID) { - THandle thePicture; + THandle thePicture; // Handle resHandle; // Str255 resName; // ResType resType; @@ -870,7 +870,7 @@ Boolean PictIDExists (short theID) thePicture = GetPicture(theID); if (thePicture == nil) { - thePicture = GetResource('Date', theID).StaticCast(); + thePicture = GetResource('Date', theID).StaticCast(); if (thePicture == nil) { foundIt = false; diff --git a/GpApp/StructuresInit.cpp b/GpApp/StructuresInit.cpp index d81945b..95e69c6 100644 --- a/GpApp/StructuresInit.cpp +++ b/GpApp/StructuresInit.cpp @@ -6,6 +6,7 @@ #include "PLResources.h" +#include "BitmapImage.h" #include "Externs.h" #include "FontFamily.h" #include "FontManager.h" @@ -60,11 +61,11 @@ extern short wasScoreboardMode; void InitScoreboardMap (void) { - Rect bounds; - THandle thePicture; - DrawSurface *wasCPort; - PLError_t theErr; - short hOffset; + Rect bounds; + THandle thePicture; + DrawSurface *wasCPort; + PLError_t theErr; + short hOffset; wasScoreboardMode = kScoreboardHigh; boardSrcRect = houseRect; @@ -79,7 +80,7 @@ void InitScoreboardMap (void) thePicture = GetPicture(kScoreboardPictID); if (thePicture == nil) RedAlert(kErrFailedGraphicLoad); - bounds = (*thePicture)->picFrame.ToRect(); + bounds = (*thePicture)->GetRect(); QOffsetRect(&bounds, -bounds.left, -bounds.top); QOffsetRect(&bounds, hOffset, 0); boardSrcMap->DrawPicture(thePicture, bounds); diff --git a/GpApp/Utilities.cpp b/GpApp/Utilities.cpp index c337608..0cfabed 100644 --- a/GpApp/Utilities.cpp +++ b/GpApp/Utilities.cpp @@ -12,6 +12,7 @@ #include "PLSound.h" #include "PLTimeTaggedVOSEvent.h" #include "QDPixMap.h" +#include "BitmapImage.h" #include "Externs.h" #include "IconLoader.h" #include "InputManager.h" @@ -251,14 +252,14 @@ void KillOffScreenBitMap (GrafPtr offScreen) void LoadGraphic (DrawSurface *surface, short resID) { - Rect bounds; - THandle thePicture; + Rect bounds; + THandle thePicture; thePicture = GetPicture(resID); if (thePicture == nil) RedAlert(kErrFailedGraphicLoad); - bounds = (*thePicture)->picFrame.ToRect(); + bounds = (*thePicture)->GetRect(); OffsetRect(&bounds, -bounds.left, -bounds.top); surface->DrawPicture(thePicture, bounds); @@ -272,7 +273,7 @@ void LoadGraphic (DrawSurface *surface, short resID) void LoadScaledGraphic (DrawSurface *surface, short resID, Rect *theRect) { - THandle thePicture; + THandle thePicture; thePicture = GetPicture(resID); if (thePicture == nil) diff --git a/PortabilityLayer/BMPFormat.h b/PortabilityLayer/BMPFormat.h index 913bae3..2b89f95 100644 --- a/PortabilityLayer/BMPFormat.h +++ b/PortabilityLayer/BMPFormat.h @@ -1,6 +1,6 @@ #pragma once -#include "PLLittleEndian.h" +#include "PLLittleEndian.h" namespace PortabilityLayer { @@ -11,14 +11,14 @@ namespace PortabilityLayer } struct BitmapFileHeader - { + { char m_id[2]; // Normally "BM" LEUInt32_t m_fileSize; LEUInt16_t m_reserved1; LEUInt16_t m_reserved2; - LEUInt32_t m_imageDataStart; + LEUInt32_t m_imageDataStart; }; - + struct BitmapInfoHeader { LEUInt32_t m_thisStructureSize; diff --git a/PortabilityLayer/BitmapImage.cpp b/PortabilityLayer/BitmapImage.cpp new file mode 100644 index 0000000..100695a --- /dev/null +++ b/PortabilityLayer/BitmapImage.cpp @@ -0,0 +1,12 @@ +#include "BMPFormat.h" +#include "BitmapImage.h" + +Rect BitmapImage::GetRect() const +{ + const PortabilityLayer::BitmapInfoHeader *infoHeader = reinterpret_cast(reinterpret_cast(this) + sizeof(PortabilityLayer::BitmapFileHeader)); + + const uint32_t width = infoHeader->m_width; + const uint32_t height = infoHeader->m_height; + + return Rect::Create(0, 0, static_cast(height), static_cast(width)); +} diff --git a/PortabilityLayer/BitmapImage.h b/PortabilityLayer/BitmapImage.h new file mode 100644 index 0000000..defa68b --- /dev/null +++ b/PortabilityLayer/BitmapImage.h @@ -0,0 +1,11 @@ +#pragma once + +#include "BMPFormat.h" +#include "SharedTypes.h" + +struct BitmapImage +{ + PortabilityLayer::BitmapFileHeader m_fileHeader; + + Rect GetRect() const; +}; diff --git a/PortabilityLayer/PLImageWidget.cpp b/PortabilityLayer/PLImageWidget.cpp index 811d5fa..c108463 100644 --- a/PortabilityLayer/PLImageWidget.cpp +++ b/PortabilityLayer/PLImageWidget.cpp @@ -15,7 +15,7 @@ namespace PortabilityLayer bool ImageWidget::Init(const WidgetBasicState &state) { - m_pict = PortabilityLayer::ResourceManager::GetInstance()->GetResource('PICT', state.m_resID).StaticCast(); + m_pict = PortabilityLayer::ResourceManager::GetInstance()->GetResource('PICT', state.m_resID).StaticCast(); if (!m_pict) return false; diff --git a/PortabilityLayer/PLImageWidget.h b/PortabilityLayer/PLImageWidget.h index 9da1979..79e2b71 100644 --- a/PortabilityLayer/PLImageWidget.h +++ b/PortabilityLayer/PLImageWidget.h @@ -3,7 +3,7 @@ #include "PLWidgets.h" #include "PLHandle.h" -struct Picture; +struct BitmapImage; namespace PortabilityLayer { @@ -17,6 +17,6 @@ namespace PortabilityLayer void DrawControl(DrawSurface *surface) override; private: - THandle m_pict; + THandle m_pict; }; } diff --git a/PortabilityLayer/PLQDOffscreen.cpp b/PortabilityLayer/PLQDOffscreen.cpp index 384f5fe..67d7519 100644 --- a/PortabilityLayer/PLQDOffscreen.cpp +++ b/PortabilityLayer/PLQDOffscreen.cpp @@ -36,9 +36,9 @@ PixMapHandle GetGWorldPixMap(DrawSurface *gworld) return gworld->m_port.GetPixMap(); } -THandle GetPicture(short resID) +THandle GetPicture(short resID) { - return PortabilityLayer::ResourceManager::GetInstance()->GetResource('PICT', resID).StaticCast(); + return PortabilityLayer::ResourceManager::GetInstance()->GetResource('PICT', resID).StaticCast(); } void OffsetRect(Rect *rect, int right, int down) diff --git a/PortabilityLayer/PLQDOffscreen.h b/PortabilityLayer/PLQDOffscreen.h index 1230e55..c7dbd80 100644 --- a/PortabilityLayer/PLQDOffscreen.h +++ b/PortabilityLayer/PLQDOffscreen.h @@ -22,7 +22,7 @@ void DisposeGWorld(DrawSurface *gworld); PixMapHandle GetGWorldPixMap(DrawSurface *gworld); -THandle GetPicture(short resID); +THandle GetPicture(short resID); void OffsetRect(Rect *rect, int right, int down); diff --git a/PortabilityLayer/PLQDraw.cpp b/PortabilityLayer/PLQDraw.cpp index 47a7005..88e8c1c 100644 --- a/PortabilityLayer/PLQDraw.cpp +++ b/PortabilityLayer/PLQDraw.cpp @@ -1,6 +1,7 @@ #include "PLQDraw.h" #include "QDManager.h" #include "QDState.h" +#include "BitmapImage.h" #include "DisplayDeviceManager.h" #include "FontFamily.h" #include "FontManager.h" @@ -22,11 +23,8 @@ #include "ScanlineMaskIterator.h" #include "QDGraf.h" #include "QDStandardPalette.h" -#include "QDPictEmitContext.h" -#include "QDPictEmitScanlineParameters.h" #include "WindowManager.h" #include "QDGraf.h" -#include "QDPictDecoder.h" #include "QDPixMap.h" #include "Vec2i.h" @@ -34,220 +32,6 @@ #include -namespace PortabilityLayer -{ - class PixMapBlitEmitter final : public QDPictEmitContext - { - public: - PixMapBlitEmitter(const Vec2i &drawOrigin, PixMapImpl *pixMap); - ~PixMapBlitEmitter(); - - bool SpecifyFrame(const Rect &rect) override; - Rect ConstrainRegion(const Rect &rect) const override; - void Start(QDPictBlitSourceType sourceType, const QDPictEmitScanlineParameters ¶ms) override; - void BlitScanlineAndAdvance(const void *) override; - bool AllocTempBuffers(uint8_t *&buffer1, size_t buffer1Size, uint8_t *&buffer2, size_t buffer2Size) override; - - private: - PixMapImpl *m_pixMap; - Vec2i m_drawOrigin; - uint8_t *m_tempBuffer; - Rect m_specFrame; - - QDPictBlitSourceType m_blitType; - QDPictEmitScanlineParameters m_params; - - size_t m_constraintRegionWidth; - size_t m_constraintRegionStartIndex; - size_t m_constraintRegionEndIndex; - size_t m_outputIndexStart; - - uint8_t m_paletteMap[256]; - bool m_sourceAndDestPalettesAreSame; - }; - - PixMapBlitEmitter::PixMapBlitEmitter(const Vec2i &drawOrigin, PixMapImpl *pixMap) - : m_pixMap(pixMap) - , m_drawOrigin(drawOrigin) - , m_tempBuffer(nullptr) - , m_sourceAndDestPalettesAreSame(false) - { - } - - PixMapBlitEmitter::~PixMapBlitEmitter() - { - if (m_tempBuffer) - PortabilityLayer::MemoryManager::GetInstance()->Release(m_tempBuffer); - } - - bool PixMapBlitEmitter::SpecifyFrame(const Rect &rect) - { - m_specFrame = rect; - return true; - } - - Rect PixMapBlitEmitter::ConstrainRegion(const Rect &rect) const - { - const Rect pixMapRect = m_pixMap->m_rect; - - const Rect2i rectInDrawSpace = Rect2i(rect) + m_drawOrigin; - - const Rect2i constrainedRectInDrawSpace = rectInDrawSpace.Intersect(Rect2i(pixMapRect)); - - // If this got completely culled away, return an empty rect, but avoid int truncation - if (!constrainedRectInDrawSpace.IsValid()) - return Rect::Create(rect.top, rect.left, rect.top, rect.left); - - // Otherwise, it should still be valid in the picture space - const Rect2i constrainedRectInPictSpace = constrainedRectInDrawSpace - m_drawOrigin; - return constrainedRectInPictSpace.ToShortRect(); - } - - void PixMapBlitEmitter::Start(QDPictBlitSourceType sourceType, const QDPictEmitScanlineParameters ¶ms) - { - // FIXME: Detect different system palette (if we ever do that) - if (QDPictBlitSourceType_IsIndexed(sourceType)) - { - if (params.m_numColors == 256 && !memcmp(params.m_colors, StandardPalette::GetInstance()->GetColors(), sizeof(RGBAColor) * 256)) - m_sourceAndDestPalettesAreSame = true; - else - { - assert(false); - } - } - - m_blitType = sourceType; - m_params = params; - - m_constraintRegionWidth = params.m_constrainedRegionRight - params.m_constrainedRegionLeft; - m_constraintRegionStartIndex = params.m_constrainedRegionLeft - params.m_scanlineOriginX; - m_constraintRegionEndIndex = params.m_constrainedRegionRight - params.m_scanlineOriginX; - - const size_t firstCol = params.m_constrainedRegionLeft + m_drawOrigin.m_x - m_pixMap->m_rect.left; - const size_t firstRow = params.m_firstY + m_drawOrigin.m_y - m_pixMap->m_rect.top; - - m_outputIndexStart = firstRow * m_pixMap->GetPitch() + firstCol; - } - - void PixMapBlitEmitter::BlitScanlineAndAdvance(const void *data) - { - const int32_t crRight = m_params.m_constrainedRegionRight; - const int32_t crLeft = m_params.m_constrainedRegionLeft; - const size_t constraintRegionStartIndex = m_constraintRegionStartIndex; - const uint8_t *dataBytes = static_cast(data); - const size_t outputIndexStart = m_outputIndexStart; - const size_t planarSeparation = m_params.m_planarSeparation; - const size_t constraintRegionWidth = m_constraintRegionWidth; - - const uint8_t *paletteMapping = nullptr; - - const uint8_t staticMapping1Bit[] = { 0, 255 }; - - void *imageData = m_pixMap->GetPixelData(); - - if (m_pixMap->GetPixelFormat() == GpPixelFormats::k8BitStandard || m_pixMap->GetPixelFormat() == GpPixelFormats::kBW1) - { - switch (m_blitType) - { - case QDPictBlitSourceType_Indexed1Bit: - for (size_t i = 0; i < constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - - const int bitShift = 7 - (itemIndex & 7); - const int colorIndex = (dataBytes[itemIndex / 8] >> bitShift) & 0x1; - static_cast(imageData)[i + outputIndexStart] = paletteMapping[colorIndex]; - } - break; - case QDPictBlitSourceType_Indexed2Bit: - for (size_t i = 0; i < constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - - const int bitShift = 6 - (2 * (itemIndex & 1)); - const int colorIndex = (dataBytes[itemIndex / 4] >> bitShift) & 0x3; - static_cast(imageData)[i + outputIndexStart] = paletteMapping[colorIndex]; - } - break; - case QDPictBlitSourceType_Indexed4Bit: - for (size_t i = 0; i < constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - - const int bitShift = 4 - (4 * (itemIndex & 1)); - const int colorIndex = (dataBytes[itemIndex / 2] >> bitShift) & 0xf; - static_cast(imageData)[i + outputIndexStart] = paletteMapping[colorIndex]; - } - break; - case QDPictBlitSourceType_Indexed8Bit: - if (m_sourceAndDestPalettesAreSame) - memcpy(static_cast(imageData) + outputIndexStart, dataBytes + constraintRegionStartIndex, m_constraintRegionWidth); - else - { - for (size_t i = 0; i < constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - const uint8_t colorIndex = dataBytes[itemIndex]; - static_cast(imageData)[i + outputIndexStart] = paletteMapping[colorIndex]; - } - } - break; - case QDPictBlitSourceType_1Bit: - for (size_t i = 0; i < constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - - const int bitShift = 7 - (itemIndex & 7); - const int colorIndex = (dataBytes[itemIndex / 8] >> bitShift) & 0x1; - static_cast(imageData)[i + outputIndexStart] = staticMapping1Bit[colorIndex]; - } - break; - case QDPictBlitSourceType_RGB15: - for (size_t i = 0; i < constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - - const uint16_t item = *reinterpret_cast(dataBytes + itemIndex * 2); - uint8_t &outputItem = static_cast(imageData)[i + outputIndexStart]; - - outputItem = StandardPalette::GetInstance()->MapColorLUT((item >> 1) & 0xf, (item >> 6) & 0xf, (item >> 11) & 0x1f); - } - break; - case QDPictBlitSourceType_RGB24_Multiplane: - for (size_t i = 0; i < m_constraintRegionWidth; i++) - { - const size_t itemIndex = i + constraintRegionStartIndex; - - uint8_t &outputItem = static_cast(imageData)[i + outputIndexStart]; - - const uint8_t r = dataBytes[itemIndex]; - const uint8_t g = dataBytes[itemIndex + planarSeparation]; - const uint8_t b = dataBytes[itemIndex + planarSeparation * 2]; - - outputItem = StandardPalette::GetInstance()->MapColorLUT(r, g, b); - } - break; - default: - assert(false); - } - } - - m_outputIndexStart += m_pixMap->GetPitch(); - } - - bool PixMapBlitEmitter::AllocTempBuffers(uint8_t *&buffer1, size_t buffer1Size, uint8_t *&buffer2, size_t buffer2Size) - { - m_tempBuffer = static_cast(PortabilityLayer::MemoryManager::GetInstance()->Alloc(buffer1Size + buffer2Size)); - if (!m_tempBuffer) - return false; - - buffer1 = m_tempBuffer; - buffer2 = m_tempBuffer + buffer1Size; - - return true; - } -} - void GetPort(GrafPtr *graf) { PL_NotYetImplemented(); @@ -820,7 +604,7 @@ int32_t DrawSurface::MeasureFontLineGap() return rfont->GetMetrics().m_linegap; } -void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds) +void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds) { if (!pictHdl) return; @@ -828,11 +612,15 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds) if (!bounds.IsValid() || bounds.Width() == 0 || bounds.Height() == 0) return; - Picture *picPtr = *pictHdl; - if (!picPtr) + BitmapImage *bmpPtr = *pictHdl; + if (!bmpPtr) return; - const Rect picRect = picPtr->picFrame.ToRect(); + const size_t bmpSize = bmpPtr->m_fileHeader.m_fileSize; + const Rect picRect = bmpPtr->GetRect(); + + if (picRect.Width() == 0 || picRect.Height() == 0) + return; if (bounds.right - bounds.left != picRect.right - picRect.left || bounds.bottom - bounds.top != picRect.bottom - picRect.top) { @@ -868,20 +656,245 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds) PortabilityLayer::PixMapImpl *pixMap = static_cast(*port->GetPixMap()); long handleSize = pictHdl.MMBlock()->m_size; - PortabilityLayer::MemReaderStream stream(picPtr, handleSize); + PortabilityLayer::MemReaderStream stream(bmpPtr, handleSize); // Adjust draw origin - const PortabilityLayer::Vec2i drawOrigin = PortabilityLayer::Vec2i(bounds.left - picPtr->picFrame.left, bounds.top - picPtr->picFrame.top); + const PortabilityLayer::Vec2i drawOrigin = PortabilityLayer::Vec2i(bounds.left, bounds.top); + const Rect targetPixMapRect = pixMap->m_rect; - switch (pixMap->GetPixelFormat()) + const int32_t truncatedTop = std::max(0, targetPixMapRect.top - bounds.top); + const int32_t truncatedBottom = std::max(0, bounds.bottom - targetPixMapRect.bottom); + const int32_t truncatedLeft = std::max(0, targetPixMapRect.left - bounds.left); + const int32_t truncatedRight = std::max(0, bounds.right - targetPixMapRect.right); + + uint8_t paletteMapping[256]; + for (int i = 0; i < 256; i++) + paletteMapping[i] = 0; + + // Parse bitmap header + const uint8_t *bmpBytes = reinterpret_cast(bmpPtr); + + PortabilityLayer::BitmapFileHeader fileHeader; + PortabilityLayer::BitmapInfoHeader infoHeader; + + memcpy(&fileHeader, bmpBytes, sizeof(fileHeader)); + memcpy(&infoHeader, bmpBytes + sizeof(fileHeader), sizeof(infoHeader)); + + const uint16_t bpp = infoHeader.m_bitsPerPixel; + + if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24) + return; + + const uint32_t numColors = infoHeader.m_numColors; + if (numColors > 256) + return; + + const uint8_t *ctabLoc = bmpBytes + sizeof(fileHeader) + infoHeader.m_thisStructureSize; + + const size_t ctabSize = infoHeader.m_numColors * sizeof(PortabilityLayer::BitmapColorTableEntry); + const size_t availCTabBytes = bmpSize - sizeof(fileHeader) - infoHeader.m_thisStructureSize; + + if (ctabSize > availCTabBytes) + return; + + if (bpp <= 8) + { + // Perform palette mapping + if (pixMap->GetPixelFormat() == GpPixelFormats::kBW1) + { + const PortabilityLayer::BitmapColorTableEntry *ctab = reinterpret_cast(ctabLoc); + for (size_t i = 0; i < numColors; i++) + { + const PortabilityLayer::BitmapColorTableEntry &ctabEntry = ctab[i]; + if (ctabEntry.m_r + ctabEntry.m_g + ctabEntry.m_b < 383) + paletteMapping[i] = 255; + else + paletteMapping[i] = 0; + } + } + else if (pixMap->GetPixelFormat() == GpPixelFormats::k8BitStandard) + { + const PortabilityLayer::BitmapColorTableEntry *ctab = reinterpret_cast(ctabLoc); + for (size_t i = 0; i < numColors; i++) + { + const PortabilityLayer::BitmapColorTableEntry &ctabEntry = ctab[i]; + paletteMapping[i] = PortabilityLayer::StandardPalette::GetInstance()->MapColorLUT(PortabilityLayer::RGBAColor::Create(ctabEntry.m_r, ctabEntry.m_g, ctabEntry.m_b, 255)); + const PortabilityLayer::RGBAColor &resultColor = PortabilityLayer::StandardPalette::GetInstance()->GetColors()[paletteMapping[i]]; + } + } + else + { + PL_NotYetImplemented(); + } + } + + const uint32_t imageDataOffset = fileHeader.m_imageDataStart; + + if (imageDataOffset > bmpSize) + return; + + const size_t availImageDataSize = bmpSize - imageDataOffset; + + const size_t sourcePitch = (bpp * infoHeader.m_width + 31) / 32 * 4; + const size_t inDataSize = sourcePitch * infoHeader.m_height; + + if (inDataSize > availImageDataSize) + return; + + const uint8_t *imageDataStart = reinterpret_cast(bmpPtr) + imageDataOffset; + const uint8_t *sourceFirstImageRowStart = imageDataStart + (infoHeader.m_height - 1) * sourcePitch; + + // Determine rect + const PortabilityLayer::Rect2i sourceRect = PortabilityLayer::Rect2i(truncatedTop, truncatedLeft, static_cast(infoHeader.m_height) - truncatedBottom, static_cast(infoHeader.m_width) - truncatedRight); + + if (sourceRect.m_topLeft.m_x >= sourceRect.m_bottomRight.m_x || sourceRect.m_topLeft.m_y >= sourceRect.m_bottomRight.m_y) + return; // Entire rect was culled away + + const uint32_t numCopyRows = static_cast(sourceRect.m_bottomRight.m_y - sourceRect.m_topLeft.m_y); + const uint32_t numCopyCols = static_cast(sourceRect.m_bottomRight.m_x - sourceRect.m_topLeft.m_x); + + const uint8_t *firstSourceRow = sourceFirstImageRowStart - static_cast(sourceRect.m_topLeft.m_y) * sourcePitch; + int32_t firstSourceCol = sourceRect.m_topLeft.m_x; + + const size_t destPitch = pixMap->GetPitch(); + uint8_t *firstDestRow = static_cast(pixMap->GetPixelData()) + destPitch * static_cast(drawOrigin.m_y + truncatedTop); + size_t firstDestCol = static_cast(drawOrigin.m_x + truncatedLeft); + + const PortabilityLayer::StandardPalette *stdPalette = PortabilityLayer::StandardPalette::GetInstance(); + + GpPixelFormat_t destFormat = pixMap->GetPixelFormat(); + switch (destFormat) { case GpPixelFormats::kBW1: case GpPixelFormats::k8BitStandard: { - PortabilityLayer::PixMapBlitEmitter blitEmitter(drawOrigin, pixMap); - PortabilityLayer::QDPictDecoder decoder; + const uint8_t *currentSourceRow = firstSourceRow; + uint8_t *currentDestRow = firstDestRow; + for (uint32_t row = 0; row < numCopyRows; row++) + { + assert(currentSourceRow >= imageDataStart && currentSourceRow <= imageDataStart + inDataSize); - decoder.DecodePict(&stream, &blitEmitter); + if (bpp == 1) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const unsigned int srcIndex = (currentSourceRow[srcColIndex / 8] >> (8 - ((srcColIndex & 7) + 1))) & 0x01; + currentDestRow[destColIndex] = paletteMapping[srcIndex]; + } + } + else if (bpp == 4) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const unsigned int srcIndex = (currentSourceRow[srcColIndex / 2] >> (8 - ((srcColIndex & 1) + 1) * 4)) & 0x0f; + currentDestRow[destColIndex] = paletteMapping[srcIndex]; + } + } + else if (bpp == 8) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const unsigned int srcIndex = currentSourceRow[srcColIndex]; + currentDestRow[destColIndex] = paletteMapping[srcIndex]; + } + } + else if (bpp == 16) + { + if (destFormat == GpPixelFormats::kBW1) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const uint8_t srcLow = currentSourceRow[srcColIndex * 2 + 0]; + const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; + + const unsigned int combinedValue = srcLow | (srcHigh << 8); + const unsigned int b = (srcLow & 0x1f); + const unsigned int g = ((srcLow >> 5) & 0x1f); + const unsigned int r = ((srcLow >> 10) & 0x1f); + + if (r + g + b > 46) + currentDestRow[destColIndex] = 0; + else + currentDestRow[destColIndex] = 1; + } + } + else + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const uint8_t srcLow = currentSourceRow[srcColIndex * 2 + 0]; + const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; + + const unsigned int combinedValue = srcLow | (srcHigh << 8); + const unsigned int b = (srcLow & 0x1f); + const unsigned int g = ((srcLow >> 5) & 0x1f); + const unsigned int r = ((srcLow >> 10) & 0x1f); + + const unsigned int xr = (r << 5) | (r >> 2); + const unsigned int xg = (g << 5) | (g >> 2); + const unsigned int xb = (b << 5) | (b >> 2); + + currentDestRow[destColIndex] = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(xr, xg, xb, 255)); + } + } + } + else if (bpp == 24) + { + if (destFormat == GpPixelFormats::kBW1) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const uint8_t srcLow = currentSourceRow[srcColIndex * 2 + 0]; + const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; + + const unsigned int combinedValue = srcLow | (srcHigh << 8); + const unsigned int b = (srcLow & 0x1f); + const unsigned int g = ((srcLow >> 5) & 0x1f); + const unsigned int r = ((srcLow >> 10) & 0x1f); + + if (r + g + b > 46) + currentDestRow[destColIndex] = 0; + else + currentDestRow[destColIndex] = 1; + } + } + else + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const unsigned int b = currentSourceRow[srcColIndex * 3 + 0]; + const unsigned int g = currentSourceRow[srcColIndex * 3 + 1]; + const unsigned int r = currentSourceRow[srcColIndex * 3 + 2]; + + currentDestRow[destColIndex] = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(r, g, b, 255)); + } + } + } + + currentSourceRow -= sourcePitch; + currentDestRow += destPitch; + } } break; default: diff --git a/PortabilityLayer/PLResourceManager.cpp b/PortabilityLayer/PLResourceManager.cpp index db5c355..044ed73 100644 --- a/PortabilityLayer/PLResourceManager.cpp +++ b/PortabilityLayer/PLResourceManager.cpp @@ -18,6 +18,7 @@ #include "VirtualDirectory.h" #include "WaveFormat.h" #include "ZipFileProxy.h" +#include "ZipFile.h" #include @@ -35,8 +36,8 @@ typedef ResourceValidationRules::ResourceValidationRule ResourceValidationRule_t namespace { - // Validation is only intended to validate enough of the file structure that constrained validation can be performed - // without needing to pass the file size + // Validation here is only intended to be minimal, to ensure later checks can determine the format size and do certain operations + // that must be valid. static bool ValidateResource(const void *res, size_t size, ResourceValidationRule_t validationRule) { switch (validationRule) @@ -57,7 +58,7 @@ namespace case ResourceValidationRules::kBMP: { - if (size < sizeof(PortabilityLayer::BitmapFileHeader)) + if (size < sizeof(PortabilityLayer::BitmapFileHeader) + sizeof(PortabilityLayer::BitmapInfoHeader)) return false; PortabilityLayer::BitmapFileHeader mainHeader; @@ -65,6 +66,19 @@ namespace if (mainHeader.m_fileSize > size) return false; + PortabilityLayer::BitmapInfoHeader infoHeader; + memcpy(&infoHeader, static_cast(res) + sizeof(mainHeader), sizeof(infoHeader)); + if (infoHeader.m_thisStructureSize < sizeof(PortabilityLayer::BitmapInfoHeader)) + return false; + + const size_t sizeForInfoHeader = size - sizeof(PortabilityLayer::BitmapFileHeader); + if (infoHeader.m_thisStructureSize > sizeForInfoHeader) + return false; + + // Dimensions need to fit in 16-bit signed space + if (infoHeader.m_width >= 0x8000 || infoHeader.m_height >= 0x8000) + return false; + return true; } break; @@ -72,6 +86,8 @@ namespace default: break; }; + + return false; } } @@ -289,17 +305,22 @@ namespace PortabilityLayer PLError_t ResourceManagerImpl::CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) { - const uint8_t blankResFileData[] = { - 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 30, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 30, 255, 255 }; - PortabilityLayer::IOStream *stream = nullptr; PLError_t error = FileManager::GetInstance()->RawOpenFileResources(virtualDir, filename, EFilePermission_Write, true, GpFileCreationDispositions::kCreateOrOverwrite, stream); if (error) return error; - if (stream->Write(blankResFileData, sizeof(blankResFileData)) != sizeof(blankResFileData)) + PortabilityLayer::ZipEndOfCentralDirectoryRecord eocd; + eocd.m_signature = PortabilityLayer::ZipEndOfCentralDirectoryRecord::kSignature; + eocd.m_thisDiskNumber = 0; + eocd.m_centralDirDisk = 0; + eocd.m_numCentralDirRecordsThisDisk = 0; + eocd.m_numCentralDirRecords = 0; + eocd.m_centralDirectorySizeBytes = 0; + eocd.m_centralDirStartOffset = 0; + eocd.m_commentLength = 0; + + if (stream->Write(&eocd, sizeof(eocd)) != sizeof(eocd)) { stream->Close(); return PLErrors::kIOError; @@ -347,12 +368,16 @@ namespace PortabilityLayer size_t numFiles = zipFileProxy->NumFiles(); - ResourceArchiveRef *refs = static_cast(mm->Alloc(sizeof(ResourceArchiveRef) * numFiles)); - if (!refs) - return nullptr; + ResourceArchiveRef *refs = nullptr; + if (numFiles > 0) + { + refs = static_cast(mm->Alloc(sizeof(ResourceArchiveRef) * numFiles)); + if (!refs) + return nullptr; - for (size_t i = 0; i < numFiles; i++) - new (refs + i) ResourceArchiveRef(); + for (size_t i = 0; i < numFiles; i++) + new (refs + i) ResourceArchiveRef(); + } void *storage = mm->Alloc(sizeof(ResourceArchive)); if (!storage) @@ -380,6 +405,11 @@ namespace PortabilityLayer extension = ".wav"; validationRule = ResourceValidationRules::kWAV; } + else if (resTypeID == ResTypeID('Date') || resTypeID == ResTypeID('PICT')) + { + extension = ".bmp"; + validationRule = ResourceValidationRules::kBMP; + } char resourceFile[64]; diff --git a/PortabilityLayer/PortabilityLayer.vcxproj b/PortabilityLayer/PortabilityLayer.vcxproj index 6e27ee9..13b03dc 100644 --- a/PortabilityLayer/PortabilityLayer.vcxproj +++ b/PortabilityLayer/PortabilityLayer.vcxproj @@ -141,6 +141,7 @@ + @@ -292,6 +293,7 @@ + diff --git a/PortabilityLayer/PortabilityLayer.vcxproj.filters b/PortabilityLayer/PortabilityLayer.vcxproj.filters index 7cb4cf1..5188a66 100644 --- a/PortabilityLayer/PortabilityLayer.vcxproj.filters +++ b/PortabilityLayer/PortabilityLayer.vcxproj.filters @@ -468,6 +468,9 @@ Header Files + + Header Files + @@ -731,5 +734,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/PortabilityLayer/QDGraf.h b/PortabilityLayer/QDGraf.h index bdcb963..6057135 100644 --- a/PortabilityLayer/QDGraf.h +++ b/PortabilityLayer/QDGraf.h @@ -16,7 +16,7 @@ namespace PortabilityLayer } struct PixMap; -struct Picture; +struct BitmapImage; struct Point; struct Rect; struct IGpDisplayDriver; @@ -88,7 +88,7 @@ struct DrawSurface final int32_t MeasureFontAscender(); int32_t MeasureFontLineGap(); - void DrawPicture(THandle pictHandle, const Rect &rect); + void DrawPicture(THandle pictHandle, const Rect &rect); void SetPattern8x8(const uint8_t *pattern); void ClearPattern(); @@ -98,8 +98,6 @@ struct DrawSurface final Rect GetClipRect() const; void SetClipRect(const Rect &rect); - void RegenerateAATable(const PortabilityLayer::RGBAColor &color, const PortabilityLayer::RGBAColor *paletteColors, size_t numColors); - // Must be the first item PortabilityLayer::QDPort m_port; diff --git a/PortabilityLayer/QDPictHeader.cpp b/PortabilityLayer/QDPictHeader.cpp index 726e81e..ec72e88 100644 --- a/PortabilityLayer/QDPictHeader.cpp +++ b/PortabilityLayer/QDPictHeader.cpp @@ -14,14 +14,21 @@ namespace PortabilityLayer } bool QDPictHeader::Load(IOStream *stream) - { - GP_STATIC_ASSERT(sizeof(Picture) == 10); + { + struct PictHeader + { + uint8_t m_size[2]; + + BERect m_rect; + }; - Picture pictHeader; - if (stream->Read(&pictHeader, sizeof(Picture)) != sizeof(Picture)) + GP_STATIC_ASSERT(sizeof(PictHeader) == 10); + + PictHeader pictHeader; + if (stream->Read(&pictHeader, sizeof(PictHeader)) != sizeof(PictHeader)) return false; - m_frame = pictHeader.picFrame.ToRect(); + m_frame = pictHeader.m_rect.ToRect(); if (!m_frame.IsValid()) return false; @@ -67,4 +74,4 @@ namespace PortabilityLayer { return m_frame; } -} \ No newline at end of file +} diff --git a/PortabilityLayer/QDStandardPalette.cpp b/PortabilityLayer/QDStandardPalette.cpp index 58f9298..92c8bbb 100644 --- a/PortabilityLayer/QDStandardPalette.cpp +++ b/PortabilityLayer/QDStandardPalette.cpp @@ -119,9 +119,9 @@ namespace PortabilityLayer uint8_t StandardPalette::MapColorAnalyticTruncated(unsigned int r, unsigned int g, unsigned int b) { - if (g <= 1 && g <= 1) + if (g <= 1 && b <= 1) { - if (b <= 1) + if (r <= 1) { // Special case low gray scale return 255 - b; diff --git a/PortabilityLayer/SharedTypes.h b/PortabilityLayer/SharedTypes.h index 838a57e..b2017ef 100644 --- a/PortabilityLayer/SharedTypes.h +++ b/PortabilityLayer/SharedTypes.h @@ -5,6 +5,8 @@ #include "PLBigEndian.h" #include "RGBAColor.h" +struct BitmapImage; + struct Point { int16_t v; @@ -63,13 +65,6 @@ struct BERegion BERect rect; }; -struct Picture -{ - uint8_t sizeLowBytes[2]; // Low-order bytes of size, deprecated - - BERect picFrame; -}; - struct BEBitMap { BERect m_bounds; diff --git a/PortabilityLayer/ZipFileProxy.cpp b/PortabilityLayer/ZipFileProxy.cpp index badb0c0..4fefc21 100644 --- a/PortabilityLayer/ZipFileProxy.cpp +++ b/PortabilityLayer/ZipFileProxy.cpp @@ -163,24 +163,30 @@ namespace PortabilityLayer return nullptr; const size_t centralDirSize = eocd.m_centralDirectorySizeBytes; - void *centralDirImage = mm->Alloc(centralDirSize); - if (!centralDirImage) - return nullptr; + void *centralDirImage = nullptr; + ZipCentralDirectoryFileHeader **centralDirFiles = nullptr; const size_t numFiles = eocd.m_numCentralDirRecords; - ZipCentralDirectoryFileHeader **centralDirFiles = static_cast(mm->Alloc(sizeof(ZipCentralDirectoryFileHeader*) * numFiles)); - if (!centralDirFiles) + if (centralDirSize > 0) { - mm->Release(centralDirImage); - return nullptr; - } + centralDirImage = mm->Alloc(centralDirSize); + if (!centralDirImage) + return nullptr; - if (stream->Read(centralDirImage, centralDirSize) != centralDirSize) - { - mm->Release(centralDirFiles); - mm->Release(centralDirImage); - return nullptr; + centralDirFiles = static_cast(mm->Alloc(sizeof(ZipCentralDirectoryFileHeader*) * numFiles)); + if (!centralDirFiles) + { + mm->Release(centralDirImage); + return nullptr; + } + + if (stream->Read(centralDirImage, centralDirSize) != centralDirSize) + { + mm->Release(centralDirFiles); + mm->Release(centralDirImage); + return nullptr; + } } bool failed = false; @@ -246,7 +252,8 @@ namespace PortabilityLayer return nullptr; } - qsort(centralDirFiles, numFiles, sizeof(ZipCentralDirectoryFileHeader*), ZipDirectorySortPredicate); + if (numFiles) + qsort(centralDirFiles, numFiles, sizeof(ZipCentralDirectoryFileHeader*), ZipDirectorySortPredicate); for (size_t i = 1; i < numFiles; i++) { diff --git a/gpr2gpa/gpr2gpa.cpp b/gpr2gpa/gpr2gpa.cpp index 3b46a68..45c1d60 100644 --- a/gpr2gpa/gpr2gpa.cpp +++ b/gpr2gpa/gpr2gpa.cpp @@ -297,12 +297,15 @@ void BMPDumperContext::BlitScanlineAndAdvance(const void *scanlineData) m_blitOrigin += m_pitchInElements; const size_t planarSeparation = m_blitParams.m_planarSeparation; + const size_t firstSrcCol = static_cast(m_blitParams.m_constrainedRegionLeft - m_blitParams.m_scanlineOriginX); + switch (m_blitSourceType) { case PortabilityLayer::QDPictBlitSourceType_1Bit: for (size_t i = 0; i < rowSize; i++) { - if (scanlineBytes[i / 8] & (0x80 >> (i & 7))) + const size_t originCol = i + firstSrcCol; + if (scanlineBytes[originCol / 8] & (0x80 >> (originCol & 7))) outRowStart[i] = PortabilityLayer::RGBAColor::Create(0, 0, 0, 255); else outRowStart[i] = PortabilityLayer::RGBAColor::Create(255, 255, 255, 255); @@ -311,35 +314,40 @@ void BMPDumperContext::BlitScanlineAndAdvance(const void *scanlineData) case PortabilityLayer::QDPictBlitSourceType_Indexed1Bit: for (size_t i = 0; i < rowSize; i++) { - const unsigned int colorIndex = (scanlineBytes[i / 8] >> (8 - ((i & 7) + 1) * 1)) & 1; + const size_t originCol = i + firstSrcCol; + const unsigned int colorIndex = (scanlineBytes[originCol / 8] >> (8 - ((originCol & 7) + 1) * 1)) & 1; outRowStart[i] = m_blitParams.m_colors[colorIndex]; } break; case PortabilityLayer::QDPictBlitSourceType_Indexed2Bit: for (size_t i = 0; i < rowSize; i++) { - const unsigned int colorIndex = (scanlineBytes[i / 4] >> (8 - ((i & 3) + 1) * 2)) & 3; + const size_t originCol = i + firstSrcCol; + const unsigned int colorIndex = (scanlineBytes[originCol / 4] >> (8 - ((originCol & 3) + 1) * 2)) & 3; outRowStart[i] = m_blitParams.m_colors[colorIndex]; } break; case PortabilityLayer::QDPictBlitSourceType_Indexed4Bit: for (size_t i = 0; i < rowSize; i++) { - const unsigned int colorIndex = (scanlineBytes[i / 2] >> (8 - ((i & 1) + 1) * 4)) & 15; + const size_t originCol = i + firstSrcCol; + const unsigned int colorIndex = (scanlineBytes[originCol / 2] >> (8 - ((originCol & 1) + 1) * 4)) & 15; outRowStart[i] = m_blitParams.m_colors[colorIndex]; } break; case PortabilityLayer::QDPictBlitSourceType_Indexed8Bit: for (size_t i = 0; i < rowSize; i++) { - const unsigned int colorIndex = scanlineBytes[i]; + const size_t originCol = i + firstSrcCol; + const unsigned int colorIndex = scanlineBytes[originCol]; outRowStart[i] = m_blitParams.m_colors[colorIndex]; } break; case PortabilityLayer::QDPictBlitSourceType_RGB15: for (size_t i = 0; i < rowSize; i++) { - const uint16_t item = *reinterpret_cast(scanlineBytes + i * 2); + const size_t originCol = i + firstSrcCol; + const uint16_t item = *reinterpret_cast(scanlineBytes + originCol * 2); PortabilityLayer::RGBAColor &outputItem = outRowStart[i]; outputItem.b = FiveToEight(item & 0x1f); @@ -351,22 +359,24 @@ void BMPDumperContext::BlitScanlineAndAdvance(const void *scanlineData) case PortabilityLayer::QDPictBlitSourceType_RGB24_Interleaved: for (size_t i = 0; i < rowSize; i++) { + const size_t originCol = i + firstSrcCol; PortabilityLayer::RGBAColor &outputItem = outRowStart[i]; - outputItem.r = scanlineBytes[i * 3 + 0]; - outputItem.g = scanlineBytes[i * 3 + 1]; - outputItem.b = scanlineBytes[i * 3 + 2]; + outputItem.r = scanlineBytes[originCol * 3 + 0]; + outputItem.g = scanlineBytes[originCol * 3 + 1]; + outputItem.b = scanlineBytes[originCol * 3 + 2]; outputItem.a = 255; } break; case PortabilityLayer::QDPictBlitSourceType_RGB24_Multiplane: for (size_t i = 0; i < rowSize; i++) { + const size_t originCol = i + firstSrcCol; PortabilityLayer::RGBAColor &outputItem = outRowStart[i]; - outputItem.r = scanlineBytes[i]; - outputItem.g = scanlineBytes[i + planarSeparation]; - outputItem.b = scanlineBytes[i + planarSeparation * 2]; + outputItem.r = scanlineBytes[originCol]; + outputItem.g = scanlineBytes[originCol + planarSeparation]; + outputItem.b = scanlineBytes[originCol + planarSeparation * 2]; outputItem.a = 255; } break; @@ -731,6 +741,7 @@ int main(int argc, const char **argv) std::vector contents; const PortabilityLayer::ResTypeID pictTypeID = PortabilityLayer::ResTypeID('PICT'); + const PortabilityLayer::ResTypeID dateTypeID = PortabilityLayer::ResTypeID('Date'); const PortabilityLayer::ResTypeID sndTypeID = PortabilityLayer::ResTypeID('snd '); for (size_t tlIndex = 0; tlIndex < typeListCount; tlIndex++) @@ -758,8 +769,7 @@ int main(int argc, const char **argv) const void *resData = res.m_resData; const size_t resSize = res.GetSize(); -#if 0 - if (typeList.m_resType == pictTypeID) + if (typeList.m_resType == pictTypeID || typeList.m_resType == dateTypeID) { PlannedEntry entry; char resName[256]; @@ -770,9 +780,7 @@ int main(int argc, const char **argv) if (ImportPICT(entry.m_contents, resData, resSize)) contents.push_back(entry); } - else -#endif - if (typeList.m_resType == sndTypeID) + else if (typeList.m_resType == sndTypeID) { PlannedEntry entry; char resName[256];