packages feed

cold-widow (empty) → 0.1.2

raw patch · 11 files changed

+416/−0 lines, 11 filesdep +basedep +bytestringdep +cold-widowsetup-changed

Dependencies added: base, bytestring, cold-widow, hspec

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Mihai Giurgeanu (c) 2016++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Mihai Giurgeanu nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,108 @@+# cold-widow++Executables and Haskell library to transfer files via QR Codes.++The idea is to generate a list of qr-coedes representing the archived+version folder. The qr-codes will be read as text values by any qr-code+reader supporting alpahnumeric encoding. The texts can be send via any+technology, like email, sms, whatsapp, skype, hangouts, etc to the final+destination. At the final destination, you feed these texts to the decoder+and get the original file structure.++## Installation++The only supported installation method is from source files,+[stack](http://www.haskellstack.org/).++## Building from source++### Prerequisites++You will need to [download and install stack](https://docs.haskellstack.org/en/stable/README/#how-to-install).++You also need [git](https://git-scm.com/) to get the latest source code.++### Get the source++    git clone https://github.com/mihaigiurgeanu/cold-widow.git+    +### Building++To build the project, you need first to run `stack setup`. This command+will make sure you have the correct haskell compiler, and, if you don't+have it, it will download and install one in a separate location in such+a way to not interract with your existing haskell environment (if you have one):++    #> cd /the/location/of/cold-widow/+    #> stack setup+    +After the setup (you only need to run setup once) you may build, test or install+the software. To build, simply issue:++    #> stack build+    +To run the tests:++    #> stack test+    +To install it in the stack's install directory, type:++    #> stack install+    +## Usage++The only functions implemented until now are encoding and decoding a file to/from+a textual form using only the alphanumeric symbols allowed in a QR Code. This will+allow you to read the generated QR Code with any QR Code reader, copy paste the+text in an email or whatever transport you choose.++To generate QR Codes you need to use external programs to archive and compress+your files, to split the archive in appropriate size to be encoded in the QR Codes.+For example:++    #> tar cv informic-0.1.0/*.patch | bzip2 -9 | split -b 2900 - informic-0.1.0/x+    +will archive the files with the extension `.patch` located in the `informic-0.1.0/`+folder, will compress the archive using `bzpi2` utility, will split the resulting+compressed archived in files named `xaa`, `xab`, `xac`, etc. of 2900 bytes each+and will put these files into `informic-0.1.0/` folder.++To encode those files using _cold-widow's encode45_ you could use the following:++    #> cd informic-0.1.0+    #> for i in x*; do encode45 $i > $i.txt; done +    +Then you should use a qr-code generator to generate one qr-code for each+`xaa.txt`, `xab.txt`, `xac.txt`, etc files generated by the above commands. Scan+the qr-codes with you mobile phone and copy-paste the text into a email message+that you can send to anyone you want.++Finally, using `decode45` you can convert the fragments of text back to the original+archive. Copy in the clipboard the text coresponding to first part (the file `xaa`+in the example above) and paste it in a file, for example in the `xaa.txt` file:++    #> decode45 xaa < xaa.txt++This will generate on disk the file named `xaa` with the same contents of the +original `xaa` file which is a part of the splited compressed archive. After+doing this for all file parts, you can use the following to obtain the original+files structure:++    #> cat x* | bzcat | tar xv++## encode45++The `encode45` utility will get a file as first argument and will output+the encoded text representing the file. The text will contain only characters+allowed by the qr-code alphanumeric mode.++To use it as a qr-code, you need to pass a maximum of about 2900 bytes file to+the `encode45` utility.++## decode45++`decode45` will read from standard output a text containing only the characters+allowed in qr-code alphanumeric mode and will decoded as a binary file. The name+of the file to which `decode45` will save the binary data _must_ be passed as+the first argument of the `decode45` method.+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cold-widow.cabal view
@@ -0,0 +1,61 @@+name:                cold-widow+version:             0.1.2+synopsis:            File transfer via QR Codes.+description:         Utilities and Haskell library to transfer files via qr-codes.+homepage:            https://github.com/mihaigiurgeanu/cold-widow#readme+license:             BSD3+license-file:        LICENSE+author:              Mihai Giurgeanu+maintainer:          mihai.giurgeau@gmail.com+copyright:           2016 Mihai Giurgeanu+category:            Utility+build-type:          Simple+cabal-version:       >=1.10+extra-doc-files:     README.md++library+  hs-source-dirs:       lib+  exposed-modules:      Codec.Binary.Coldwidow+  default-language:     Haskell2010+  build-depends:        base >= 4.7 && < 5,+                        bytestring++Executable cold-widow+  hs-source-dirs:      src+  main-is:             Main.hs+  default-language:    Haskell2010+  build-depends:       base >= 4.7 && < 5++executable encode45+  hs-source-dirs:       encode+  main-is:              Main.hs+  default-language:     Haskell2010+  build-depends:        base >= 4.7 && < 5,+                        bytestring,+                        cold-widow++executable decode45+  hs-source-dirs:       decode+  main-is:              Main.hs+  default-language:     Haskell2010+  build-depends:        base >= 4.7 && < 5,+                        bytestring,+                        cold-widow++executable compact-decode45+  hs-source-dirs:       compact-decode+  main-is:              Main.hs+  default-language:     Haskell2010+  build-depends:        base >= 4.7 && < 5,+                        bytestring++Test-Suite cold-widow-tests+  hs-source-dirs:       tests+  type:                 exitcode-stdio-1.0+  main-is:              Spec.hs+  default-language:     Haskell2010+  other-modules:        Codec.Binary.ColdwidowSpec+  build-depends:        base >= 4.7 && < 5,+                        hspec,+                        bytestring,+                        cold-widow
+ compact-decode/Main.hs view
@@ -0,0 +1,5 @@+-- compact-decode.hs+-- A small variant of decode, meant to have very small source code++module Main where{import System.Environment (getArgs);import qualified Data.ByteString.Lazy as B;import System.IO (withBinaryFile, IOMode(..));import Data.Word (Word8);import Numeric (readInt);import Data.Maybe (fromJust, isJust);import Data.List (elemIndex);import Data.Bits (shiftR);main=do{as<-getArgs;let {fn = as!!0};t<-getContents;let{(z, nz)=span (=='0') t};withBinaryFile fn WriteMode (\h -> do {mapM_ (\_ -> B.hPut h (B.singleton 0)) z;if null nz then return () else B.hPut h $ ui $ dcd $ filter (\c -> c /= '\n' && c/= '\r') nz;});};cs ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";b=45;dcd e=let{p=rdi e}in case p of{[(val, [])]->val;otherwise->error $ "Parse error at: " ++ (take 10 $ snd $ p !! 0);};ui 0=B.singleton 0;ui x=B.pack $ ui' x [];rdi=readInt b iD fD;iD d=isJust $ elemIndex d cs;fD d = fromJust $ elemIndex d cs;ui' 0 r = r;ui' v r = ui' (v `shiftR` 8) $ (fromInteger v :: Word8) : r;}+
+ decode/Main.hs view
@@ -0,0 +1,27 @@+-- File: decode/Main.hs++module Main where++import System.Environment (getArgs)+import qualified Data.ByteString.Lazy as B+import System.IO (withBinaryFile, IOMode(..))+import Codec.Binary.Coldwidow++main :: IO ()+main = do +  args <- getArgs+  let fileName = args !! 0+  encodedText <- getContents+  let (zeroes, nonzeroes) = span (=='0') encodedText+  withBinaryFile+    fileName+    WriteMode+    (\h -> do+        mapM_ (\_ -> B.hPut h (B.singleton 0)) zeroes+        if null nonzeroes+          then return ()+          else B.hPut h $ unpackInteger $ decode $ filter (\c -> c /= '\n' && c/= '\r') nonzeroes)++++
+ encode/Main.hs view
@@ -0,0 +1,20 @@+-- File: encode/Main.hs++module Main where++import System.Environment (getArgs)+import qualified Data.ByteString.Lazy as B++import Codec.Binary.Coldwidow++main :: IO ()+main = do +  args <- getArgs+  let fileName = args !! 0+  bytes <- B.readFile fileName+  let (zeroes, nonzeroes) = B.span (==0) bytes+  mapM_ (\_ -> putStr "0") (B.unpack zeroes)+  if B.null nonzeroes+    then return ()+    else putStr $ encode $ packInteger nonzeroes+
+ lib/Codec/Binary/Coldwidow.hs view
@@ -0,0 +1,88 @@+{- |+Module:         Codec.Binary.Coldwidow+Description:    Base45 encoding/decoding ++QR Code alphanumeric mode accepts a set of 45 characters. This module offers+functions to encode/decode binary data to/from text representation using+only the 45 characters allowed by the qr-code alphanumeric mode.+-}+module Codec.Binary.Coldwidow (encode, decode, packInteger, unpackInteger) where++import Data.Bits (shiftL, (.|.), shiftR)+import Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString.Lazy as B+import Data.Word (Word8)+import Numeric (showIntAtBase, readInt)+import Data.List (elemIndex)+import Data.Maybe (fromJust, isJust)+++chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',+         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',+         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',+         'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*',+         '+', '-', '.', '/', ':']++base = 45++-- external inteface++-- |Encodes binary data into a String. The resulting string will contain+-- only the 45 characters allowed by the qr-code alphanumeric mode. The+-- binary data to be encoded should be represented as a Haskell Integer. To+-- convert a ByteString to a Haskell Integer you can use the 'packInteger'+-- function defined bellow.+encode :: Integer -> String+encode x = showIntAtBase base toDigit x ""++-- |Converts a BinaryString to an Integer. This is used to represent binary+-- data as a Haskell Integer tha can be passed to 'encode' function defined above.+packInteger :: ByteString -> Integer+packInteger s = packInteger' (B.unpack s) 0++-- |Decodes binary data from its text representation. The text representation of+-- data, obtained with the 'encode' function defined above, will contain only+-- characters allowed in the qr-code alphanumeric mode. The decoded binary data+-- returned by this function will be represented as a Haskell Integer. To convert+-- it into a BinaryString you can use the 'unpackInteger' function defined bellow.+decode :: String -> Integer+decode encoded = let parsed = readEncodedInt encoded+                 in case parsed of+                      [(val, [])] -> val+                      otherwise -> error $ "Error parsing encoded value."++parseMessages+                        where+                          parseMessages = concatMap parseMessage parsed++-- |Converts a Haskell Integer into a ByteString. The Integer holds the binary+-- represantation of the data you obtain by using the `decode` function defined+-- above. You can use the ByteString represantation to, for example, save the+-- binary data into a file.+unpackInteger :: Integer -> ByteString+unpackInteger 0 = B.singleton 0+unpackInteger x = B.pack $ unpackInteger' x []++-- internal functions++toDigit :: Int -> Char +toDigit i = chars !! i -- TODO: make a more efficient implementation++readEncodedInt :: ReadS Integer+readEncodedInt = readInt base isDigit fromDigit++isDigit :: Char -> Bool+isDigit digit = isJust $ elemIndex digit chars++fromDigit :: Char -> Int+fromDigit digit = fromJust $ elemIndex digit chars++packInteger' :: [Word8] -> Integer -> Integer+packInteger' [] result = result+packInteger' (d:ds) result = packInteger' ds ((fromIntegral d) .|. (result `shiftL` 8))++unpackInteger' :: Integer -> [Word8] -> [Word8]+unpackInteger' 0 result = result+unpackInteger' value result = unpackInteger' (value `shiftR` 8) $ (fromInteger value :: Word8) : result++parseMessage :: (Integer, String) -> String+parseMessage (parsed, remainder) = "\n\tStopped at: " ++ (take 20 remainder)+
+ src/Main.hs view
@@ -0,0 +1,5 @@+module Main where++main :: IO ()+main = do+  putStrLn "hello world"
+ tests/Codec/Binary/ColdwidowSpec.hs view
@@ -0,0 +1,68 @@+-- File: tests/Codec/Binary/ColdwidowSpec.hs++module Codec.Binary.ColdwidowSpec (spec) where++import Test.Hspec+import Codec.Binary.Coldwidow++import Data.ByteString.Lazy (singleton, pack)++spec :: Spec+spec = do+  describe "encode" $ do+    it "returns character \"0\" when encoding value 0" $+      encode 0 `shouldBe` "0"+    it "returns character \":\" when encoding vlaue 44" $+      encode 44 `shouldBe` ":"+    it "returns characters \"10\" when encoding value 45" $+      encode 45 `shouldBe` "10"+    it "returns charcters \"11\" when encoding value 46" $+      encode 46 `shouldBe` "11"+    it "returns charcters \"1:\" when encoding value 89" $+      encode 89 `shouldBe` "1:"+    it "returns characters \":0\" when encoding value 45*44" $+      encode (45*44) `shouldBe` ":0"+    it "returns characters \"::\" when encoding value 45*44+44" $+      encode (45*44+44) `shouldBe` "::"+      +  describe "decode" $ do+    it "decodes \"0\" as 0" $+      decode "0" `shouldBe` 0+    it "decodes \":\" as 44" $+      decode ":" `shouldBe` 44+    it "decodes \"10\" as 45" $+      decode "10" `shouldBe` 45+    it "decodes \"11\" as 46" $+      decode "11" `shouldBe` 46+    it "decodes \"1:\" as 89" $+      decode "1:" `shouldBe` 89+    it "decodes \":0\" as 45*44" $+      decode ":0" `shouldBe` (45*44)+    it "decodes \"::\" as 45*44+44" $+      decode "::" `shouldBe` (45*44+44)+    it "decodes \"Q\" as 26" $+      decode "Q" `shouldBe` 26++  describe "packInteger" $ do+    it "packs [0] as 0" $+      packInteger (singleton 0) `shouldBe` 0+    it "packs [0, 0] as 0" $+      packInteger (pack [0, 0]) `shouldBe` 0+    it "packs [1] as 1" $+      packInteger (singleton 1) `shouldBe` 1+    it "packs [0, 1] as 1" $+      packInteger (pack [0, 1]) `shouldBe` 1+    it "packs [1, 0] as 256" $+      packInteger (pack [1, 0]) `shouldBe` 256++  describe "unpackInteger" $ do+    it "unpacks 0 as [0]" $+      unpackInteger 0 `shouldBe` (singleton 0)+    it "unpacks 1 as [1]" $+      unpackInteger 1 `shouldBe` (singleton 1)+    it "unpacks 256 as [1, 0]" $+      unpackInteger 256 `shouldBe` (pack [1, 0])+    it "unpacks 65535 as [255, 255]" $+      unpackInteger 65535 `shouldBe` (pack [255, 255])+    it "unpacks 1+2*256+3*256*256+4*256*256*256 as [4, 3, 2, 1]" $+      unpackInteger (1+2*256+3*256*256+4*256*256*256) `shouldBe` (pack [4, 3, 2, 1])
+ tests/Spec.hs view
@@ -0,0 +1,2 @@+-- File: tests/Spec.hs+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}