diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Zip 0.1.3
+
+* Improved speed of detection of invalid archives.
+
+* Introduced `getEntrySource` function.
+
 ## Zip 0.1.2
 
 * Relaxed dependency on `semigroups`.
diff --git a/Codec/Archive/Zip.hs b/Codec/Archive/Zip.hs
--- a/Codec/Archive/Zip.hs
+++ b/Codec/Archive/Zip.hs
@@ -58,6 +58,7 @@
   , doesEntryExist
   , getEntryDesc
   , getEntry
+  , getEntrySource
   , sourceEntry
   , saveEntry
   , checkEntry
@@ -245,6 +246,20 @@
   -> ZipArchive ByteString -- ^ Contents of the entry
 getEntry s = sourceEntry s (CL.foldMap id)
 
+-- | Get entry source.
+--
+-- Throws: 'EntryDoesNotExist'.
+
+getEntrySource
+  :: EntrySelector
+  -> ZipArchive (Source (ResourceT IO) ByteString)
+getEntrySource s = do
+  path  <- getFilePath
+  mdesc <- M.lookup s <$> getEntries
+  case mdesc of
+    Nothing   -> throwM (EntryDoesNotExist path s)
+    Just desc -> return (I.sourceEntry path desc True)
+
 -- | Stream contents of archive entry to specified 'Sink'.
 --
 -- Throws: 'EntryDoesNotExist'.
@@ -257,11 +272,8 @@
   -> ZipArchive a
      -- ^ Contents of the entry (if found)
 sourceEntry s sink = do
-  path  <- getFilePath
-  mdesc <- M.lookup s <$> getEntries
-  case mdesc of
-    Nothing   -> throwM (EntryDoesNotExist path s)
-    Just desc -> liftIO . runResourceT $ I.sourceEntry path desc True $$ sink
+  src <- getEntrySource s
+  (liftIO . runResourceT) (src $$ sink)
 
 -- | Save specific archive entry as a file in the file system.
 --
diff --git a/Codec/Archive/Zip/Internal.hs b/Codec/Archive/Zip/Internal.hs
--- a/Codec/Archive/Zip/Internal.hs
+++ b/Codec/Archive/Zip/Internal.hs
@@ -786,16 +786,17 @@
   where
 
     sizeCheck = do
-      tooSmall <- (< 22) <$> hFileSize h
-      if tooSmall
+      fsize    <- hFileSize h
+      let limit = max 0 (fsize - 0xffff - 22)
+      if fsize < 22
         then return Nothing
-        else hSeek h SeekFromEnd (-22) >> loop
+        else hSeek h SeekFromEnd (-22) >> loop limit
 
-    loop = do
+    loop limit = do
       sig <- getNum getWord32le 4
       pos <- subtract 4 <$> hTell h
-      let again = hSeek h AbsoluteSeek (pos - 1) >> loop
-          done  = pos == 0
+      let again = hSeek h AbsoluteSeek (pos - 1) >> loop limit
+          done  = pos <= limit
       if sig == 0x06054b50
         then do
           result <- checkComment pos >>+ checkCDSig >>+ checkZip64
diff --git a/zip.cabal b/zip.cabal
--- a/zip.cabal
+++ b/zip.cabal
@@ -31,7 +31,7 @@
 -- POSSIBILITY OF SUCH DAMAGE.
 
 name:                 zip
-version:              0.1.2
+version:              0.1.3
 cabal-version:        >= 1.10
 license:              BSD3
 license-file:         LICENSE.md
@@ -106,7 +106,7 @@
                     , text             >= 0.2 && < 1.3
                     , time             >= 1.4 && < 1.7
                     , transformers     >= 0.4 && < 0.6
-                    , zip              >= 0.1.2
+                    , zip              >= 0.1.3
   default-language:   Haskell2010
 
 benchmark bench
@@ -119,7 +119,7 @@
     ghc-options:      -O2 -Wall
   build-depends:      base             >= 4.8 && < 5
                     , criterion        >= 1.0
-                    , zip              >= 0.1.2
+                    , zip              >= 0.1.3
   default-language:   Haskell2010
 
 source-repository head
