Skip to content

Instantly share code, notes, and snippets.

@ion1
Forked from cmouse/gist:6029348
Last active December 19, 2015 22:48
Show Gist options
  • Save ion1/6029868 to your computer and use it in GitHub Desktop.
Save ion1/6029868 to your computer and use it in GitHub Desktop.
% dist/build/base64-check/base64-check
*** Failed! Falsifiable (after 18 tests and 3 shrinks):
[0,0,62]
% dist/build/base64-check/base64-check
Passed:
[]
Passed:
[]
Passed:
[1]
Passed:
[0,2]
Passed:
[0,2,2,1]
Passed:
[4,1]
Passed:
[0,3,2,0]
Passed:
[1,2,0,2,1]
Passed:
[8,2,1,8,5,7]
Passed:
[0,0,6,0,0,0]
Passed:
[3,12,6,4,8]
Passed:
[6,16,0,11,12,1]
Passed:
[11,1,13]
Passed:
[29,16,29,14,5,29,10,11,14]
Passed:
[16,17,5,23,19,8]
Passed:
[55,20,27,24,11,40,23,57,48,52,34,47,35]
Passed:
[13,5,53,39,58,51,52,20,35]
Failed:
[0,46,62,54,61,38,44,4,52,49,19,49,49]
*** Failed! Passed:
[]
Passed:
[44,4,52,49,19,49,49]
Failed:
[0,46,62,54,61,38,49]
Passed:
[]
Passed:
[54,61,38,49]
Failed:
[0,46,62,49]
Passed:
[]
Passed:
[62,49]
Passed:
[0,46]
Passed:
[46,62,49]
Passed:
[0,62,49]
Passed:
[0,46,49]
Failed:
[0,46,62]
Passed:
[]
Passed:
[46,62]
Passed:
[0,62]
Passed:
[0,46]
Failed:
[0,0,62]
Passed:
[]
Passed:
[0,62]
Passed:
[0,62]
Passed:
[0,0]
Passed:
[0,0,0]
Passed:
[0,0,31]
Passed:
[0,0,47]
Passed:
[0,0,55]
Passed:
[0,0,59]
Passed:
[0,0,61]
Falsifiable (after 18 tests and 4 shrinks):
[0,0,62]
name: base64-check
version: 0.0.1
category: Data
build-type: Simple
cabal-version: >=1.8
executable base64-check
main-is: Check.hs
c-sources: base64.c
include-dirs: .
build-depends: base == 4.6.*
, base64-bytestring == 1.0.*
, bytestring == 0.10.*
, QuickCheck == 2.5.*
#include <stddef.h>
#include <stdint.h>
int base64num(int ch) {
if (ch == '=') return 0;
if (ch == '/') return 63; // bug was these
if (ch == '+') return 61; // two lines
if (ch >= 'a') return ch-'a'+26;
if (ch >= 'A') return ch-'A';
if (ch >= '0') return ch-'0'+52;
return 0;
}
size_t base642raw(const char *input, size_t ilen, unsigned char *output, size_t olen)
{
if (!ilen||ilen%4) return 0; // bad input
size_t i,o,k;
uint32_t n=0;
int rem = 0;
for(i=0,o=0;i<ilen && o+3<olen;i+=4) {
n=(base64num(input[i])<<18)+(base64num(input[i+1])<<12)+(base64num(input[i+2])<<6)+base64num(input[i+3]);
// decode 3 chars
output[o]=(n>>16)&0xff; o++;
output[o]=(n>>8)&0xff; o++;
output[o]=n&0xff; o++;
}
// handle remainder
for(k=ilen-4;k<ilen;k++) rem += (input[k]=='=');
return o-rem;
}
#ifndef INCLUDE_base64_h
#define INCLUDE_base64_h
int base64num(int ch);
size_t base642raw(const char *input, size_t ilen, unsigned char *output, size_t olen);
#endif
{-# LANGUAGE ForeignFunctionInterface #-}
module Main (main) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64 as Base64
import qualified Data.ByteString.Internal as BS
import Data.ByteString.Unsafe
import Foreign hiding (unsafePerformIO)
import Foreign.C
import System.IO.Unsafe
import Test.QuickCheck
foreign import ccall "base64.h base642raw"
c'base642raw :: Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO CSize
main :: IO ()
main = quickCheckWith stdArgs{ maxSuccess = 10000 } prop_id
prop_id :: [Word8] -> Bool
prop_id ws = base642raw (Base64.encode bs) == bs
where bs = BS.pack ws
base642raw :: ByteString -> ByteString
base642raw bs = unsafePerformIO $
unsafeUseAsCStringLen bs $ \(inp, ilen) -> do
let olen = ilen -- XXX: 3/4
outp <- mallocForeignPtrArray olen
o <- withForeignPtr outp $ \outp' ->
c'base642raw inp (fromIntegral ilen) outp' (fromIntegral olen)
return $! BS.fromForeignPtr (castCCharWord8 outp) 0 (fromIntegral o)
where
castCCharWord8 :: ForeignPtr CChar -> ForeignPtr Word8
castCCharWord8 = castForeignPtr
import Distribution.Simple
main = defaultMain
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment