{-# LANGUAGE RecordWildCards #-}

-- |
-- Module: Codec.RPM.Types
-- Copyright: (c) 2016-2017 Red Hat, Inc.
-- License: LGPL
--
-- Maintainer: https://github.com/weldr
-- Stability: stable
-- Portability: portable

module Codec.RPM.Types(RPM(..),
                       Lead(..),
                       Header(..),
                       SectionHeader(..))

 where

import qualified Data.ByteString as BS
import           Data.Word(Word8, Word16, Word32)
import           Text.PrettyPrint.HughesPJClass(Pretty(..))
import           Text.PrettyPrint(($$), hcat, nest, text, vcat)

import Codec.RPM.Tags

-- | The top level RPM record.  This contains everything in an RPM file, except for the
-- magic value.
data RPM = RPM {
    -- | The 'Lead', an obsolete record used for identifying RPMs.
    RPM -> Lead
rpmLead :: Lead,
    -- | Special 'Header' entries that can be used to verify the integrity of an RPM.  This
    -- is represented as a list because it is technically possible for there to be multiple
    -- signature headers, but in practice there is only ever one.  This is the case even if
    -- multiple signatures are present.  This situation will be represented by multiple 'Tag's
    -- that can be examined to get each signature.  When checking signatures, note that they
    -- only apply to the 'rpmHeaders' and the 'rpmArchive'.
    RPM -> [Header]
rpmSignatures :: [Header],
    -- | 'Header' entries that contain all the metadata about an RPM.  There could technically
    -- be several entries here too, but in practice there is only ever one.  It is likely
    -- that each 'Header' will contain many 'Tag's, as RPMs tend to have a large amount of
    -- metadata.
    RPM -> [Header]
rpmHeaders :: [Header],
    -- | The contents of the RPM, stored as a compressed CPIO archive.
    RPM -> ByteString
rpmArchive :: BS.ByteString }
 deriving(RPM -> RPM -> Bool
(RPM -> RPM -> Bool) -> (RPM -> RPM -> Bool) -> Eq RPM
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RPM -> RPM -> Bool
$c/= :: RPM -> RPM -> Bool
== :: RPM -> RPM -> Bool
$c== :: RPM -> RPM -> Bool
Eq, Int -> RPM -> ShowS
[RPM] -> ShowS
RPM -> String
(Int -> RPM -> ShowS)
-> (RPM -> String) -> ([RPM] -> ShowS) -> Show RPM
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RPM] -> ShowS
$cshowList :: [RPM] -> ShowS
show :: RPM -> String
$cshow :: RPM -> String
showsPrec :: Int -> RPM -> ShowS
$cshowsPrec :: Int -> RPM -> ShowS
Show)

instance Pretty RPM where
    pPrint :: RPM -> Doc
pPrint RPM{..} =
        [Doc] -> Doc
vcat [ String -> Doc
text "RPM:",
               Int -> Doc -> Doc
nest 2 (String -> Doc
text "rpmLead = "    Doc -> Doc -> Doc
$$ Int -> Doc -> Doc
nest 2 (Lead -> Doc
forall a. Pretty a => a -> Doc
pPrint Lead
rpmLead)),
               Int -> Doc -> Doc
nest 2 (String -> Doc
text "rpmSignatures = " Doc -> Doc -> Doc
$$ Int -> Doc -> Doc
nest 2 ([Doc] -> Doc
vcat ([Doc] -> Doc) -> [Doc] -> Doc
forall a b. (a -> b) -> a -> b
$ (Header -> Doc) -> [Header] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map Header -> Doc
forall a. Pretty a => a -> Doc
pPrint [Header]
rpmSignatures)),
               Int -> Doc -> Doc
nest 2 (String -> Doc
text "rpmHeaders = " Doc -> Doc -> Doc
$$ Int -> Doc -> Doc
nest 2 ([Doc] -> Doc
vcat ([Doc] -> Doc) -> [Doc] -> Doc
forall a b. (a -> b) -> a -> b
$ (Header -> Doc) -> [Header] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map Header -> Doc
forall a. Pretty a => a -> Doc
pPrint [Header]
rpmHeaders)),
               Int -> Doc -> Doc
nest 2 (String -> Doc
text "rpmArchive = ...") ]

-- | Following the magic value that identifies a data stream as an RPM, the Lead is the very
-- first part of the file.  Due to its small size and inflexibility, it is largely obsolete
-- and its use is discouraged even inside of the RPM library.  It is generally only used as
-- additional help beyond the magic value in verifying something is an RPM.  The lead is
-- only exposed here for completeness.
data Lead = Lead {
    -- | The major version number of this RPM, for instance 0x03 for version 3.x.
    Lead -> Word8
rpmMajor    :: Word8,
    -- | The minor version number of this RPM, for instance 0x00 for version 3.0.
    Lead -> Word8
rpmMinor    :: Word8,
    -- | Is this a binary package (0x0000) or a source package (0x0001)?  Other types
    -- may be defined in the future.
    Lead -> Word16
rpmType     :: Word16,
    -- | What platform was this package built for?  x86 is 0x0001.  Many other values
    -- are defined.  See \/usr\/lib\/rpm\/rpmrc for the possibilities.
    Lead -> Word16
rpmArchNum  :: Word16,
    -- | The package name, as a NEVRA.  This name is constrained to 66 bytes.  Shorter
    -- names are padded with nulls.
    Lead -> String
rpmName     :: String,
    -- | What operating system was this package built for?  Linux is 0x0001.  Many other
    -- values are defined.  See \/usr\/lib\/rpm\/rpmrc for the possibilities.
    Lead -> Word16
rpmOSNum    :: Word16,
    -- | What type of signature is used in this RPM?  For now, this appears to always
    -- be set to 0x0005.
    Lead -> Word16
rpmSigType  :: Word16 }
 deriving(Lead -> Lead -> Bool
(Lead -> Lead -> Bool) -> (Lead -> Lead -> Bool) -> Eq Lead
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Lead -> Lead -> Bool
$c/= :: Lead -> Lead -> Bool
== :: Lead -> Lead -> Bool
$c== :: Lead -> Lead -> Bool
Eq, Int -> Lead -> ShowS
[Lead] -> ShowS
Lead -> String
(Int -> Lead -> ShowS)
-> (Lead -> String) -> ([Lead] -> ShowS) -> Show Lead
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Lead] -> ShowS
$cshowList :: [Lead] -> ShowS
show :: Lead -> String
$cshow :: Lead -> String
showsPrec :: Int -> Lead -> ShowS
$cshowsPrec :: Int -> Lead -> ShowS
Show)

instance Pretty Lead where
    pPrint :: Lead -> Doc
pPrint Lead{..} =
        [Doc] -> Doc
vcat [ String -> Doc
text "Lead:",
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmMajor:   ", String -> Doc
text (Word8 -> String
forall a. Show a => a -> String
show Word8
rpmMajor) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmMinor:   ", String -> Doc
text (Word8 -> String
forall a. Show a => a -> String
show Word8
rpmMinor) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmType:    ", String -> Doc
text (Word16 -> String
forall a. Show a => a -> String
show Word16
rpmType) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmArchNum: ", String -> Doc
text (Word16 -> String
forall a. Show a => a -> String
show Word16
rpmArchNum) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmName:    ", String -> Doc
text String
rpmName ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmOSNum:   ", String -> Doc
text (Word16 -> String
forall a. Show a => a -> String
show Word16
rpmOSNum) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "rpmSigType: ", String -> Doc
text (Word16 -> String
forall a. Show a => a -> String
show Word16
rpmSigType) ] ]

-- | A Header represents a block of metadata.  It is used twice in the RPM - as the
-- representation for signatures and as the representation for regular metadata.  Internally,
-- the header is a list of tag descriptors followed by a data store.  These descriptors
-- index into the store and explain what type of thing should be found and how many things
-- should be read.
--
-- Here, the hard work of figuring that out is already done and the results provided as a
-- list of 'Tag's.  The raw store itself is provided for completeness, in case further
-- processing needs to be done on the RPM.  For most users, this will never be needed.
data Header = Header {
    -- | Each header begins with its own 'SectionHeader', describing what type of header
    -- follows and how many entries that header contains.
    Header -> SectionHeader
headerSectionHeader :: SectionHeader,
    -- | A list of 'Tag' entries and their values.  There are many, many types of tags.
    Header -> [Tag]
headerTags :: [Tag],
    -- | The raw header store.
    Header -> ByteString
headerStore :: BS.ByteString }
 deriving(Header -> Header -> Bool
(Header -> Header -> Bool)
-> (Header -> Header -> Bool) -> Eq Header
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Header -> Header -> Bool
$c/= :: Header -> Header -> Bool
== :: Header -> Header -> Bool
$c== :: Header -> Header -> Bool
Eq, Int -> Header -> ShowS
[Header] -> ShowS
Header -> String
(Int -> Header -> ShowS)
-> (Header -> String) -> ([Header] -> ShowS) -> Show Header
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Header] -> ShowS
$cshowList :: [Header] -> ShowS
show :: Header -> String
$cshow :: Header -> String
showsPrec :: Int -> Header -> ShowS
$cshowsPrec :: Int -> Header -> ShowS
Show)

instance Pretty Header where
    pPrint :: Header -> Doc
pPrint Header{..} =
        [Doc] -> Doc
vcat [ String -> Doc
text "Header:",
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ String -> Doc
text "headerSectionHeader = " Doc -> Doc -> Doc
$$ Int -> Doc -> Doc
nest 2 (SectionHeader -> Doc
forall a. Pretty a => a -> Doc
pPrint SectionHeader
headerSectionHeader),
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ String -> Doc
text "headerTags = "          Doc -> Doc -> Doc
$$ Int -> Doc -> Doc
nest 2 ([Doc] -> Doc
vcat ([Doc] -> Doc) -> [Doc] -> Doc
forall a b. (a -> b) -> a -> b
$ (Tag -> Doc) -> [Tag] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map Tag -> Doc
forall a. Pretty a => a -> Doc
pPrint [Tag]
headerTags),
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ String -> Doc
text "headerStore = ..." ]

-- | The SectionHeader is useful in parsing an RPM.  It allows for figuring out where
-- each section occurs, how large it is, and so forth.  It is likely not useful for
-- consumers of this libary.  Just like with the top-level 'RPM' record, section headers
-- are preceeded with a magic value that is not exposed here.
data SectionHeader = SectionHeader {
    -- | The version of this header structure, currently only 0x01.
    SectionHeader -> Word8
sectionVersion  :: Word8,
    -- | How many 'Tag' entries are stored in this header?
    SectionHeader -> Word32
sectionCount    :: Word32,
    -- | What is the size of the data store in this header?
    SectionHeader -> Word32
sectionSize     :: Word32 }
 deriving(SectionHeader -> SectionHeader -> Bool
(SectionHeader -> SectionHeader -> Bool)
-> (SectionHeader -> SectionHeader -> Bool) -> Eq SectionHeader
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SectionHeader -> SectionHeader -> Bool
$c/= :: SectionHeader -> SectionHeader -> Bool
== :: SectionHeader -> SectionHeader -> Bool
$c== :: SectionHeader -> SectionHeader -> Bool
Eq, Int -> SectionHeader -> ShowS
[SectionHeader] -> ShowS
SectionHeader -> String
(Int -> SectionHeader -> ShowS)
-> (SectionHeader -> String)
-> ([SectionHeader] -> ShowS)
-> Show SectionHeader
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SectionHeader] -> ShowS
$cshowList :: [SectionHeader] -> ShowS
show :: SectionHeader -> String
$cshow :: SectionHeader -> String
showsPrec :: Int -> SectionHeader -> ShowS
$cshowsPrec :: Int -> SectionHeader -> ShowS
Show)

instance Pretty SectionHeader where
    pPrint :: SectionHeader -> Doc
pPrint SectionHeader{..} =
        [Doc] -> Doc
vcat [ String -> Doc
text "SectionHeader:",
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "sectionHeader: ", String -> Doc
text (Word8 -> String
forall a. Show a => a -> String
show Word8
sectionVersion) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "sectionCount:  ", String -> Doc
text (Word32 -> String
forall a. Show a => a -> String
show Word32
sectionCount) ],
               Int -> Doc -> Doc
nest 2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
hcat [ String -> Doc
text "sectionSize:   ", String -> Doc
text (Word32 -> String
forall a. Show a => a -> String
show Word32
sectionSize) ] ]