1//Command line tool capable of steganography encoding and decoding any file within given images as carriers 2package main 3 4import ( 5 "flag" 6 "fmt" 7 "github.com/DimitarPetrov/stegify/steg" 8 "os" 9 "strings" 10) 11 12const encode = "encode" 13const decode = "decode" 14 15type sliceFlag []string 16 17func (sf *sliceFlag) String() string { 18 return strings.Join(*sf, " ") 19} 20 21func (sf *sliceFlag) Set(value string) error { 22 *sf = append(*sf, value) 23 return nil 24} 25 26var carrierFilesSlice sliceFlag 27var carrierFiles = flag.String("carriers", "", "carrier files in which the data is encoded (separated by space)") 28var dataFile = flag.String("data", "", "data file which is being encoded in the carrier") 29var resultFilesSlice sliceFlag 30var resultFiles = flag.String("results", "", "names of the result files (separated by space)") 31 32func init() { 33 flag.StringVar(carrierFiles, "c", "", "carrier files in which the data is encoded (separated by space, shorthand for --carriers)") 34 flag.Var(&carrierFilesSlice, "carrier", "carrier file in which the data is encoded (could be used multiple times for multiple carriers)") 35 flag.StringVar(dataFile, "d", "", "data file which is being encoded in the carrier (shorthand for --data)") 36 flag.Var(&resultFilesSlice, "result", "name of the result file (could be used multiple times for multiple result file names)") 37 flag.StringVar(resultFiles, "r", "", "names of the result files (separated by space, shorthand for --results)") 38 39 flag.Usage = func() { 40 fmt.Fprintln(os.Stdout, "Usage: stegify [encode/decode] [flags...]") 41 flag.PrintDefaults() 42 fmt.Fprintln(os.Stdout, `NOTE: When multiple carriers are provided with different kinds of flags, the names provided through "carrier" flag are taken first and with "carriers"/"c" flags second. Same goes for the "result"/"results" flags.`) 43 fmt.Fprintln(os.Stdout, `NOTE: When no results are provided a default values will be used for the names of the results.`) 44 } 45} 46 47func main() { 48 operation := parseOperation() 49 flag.Parse() 50 carriers := parseCarriers() 51 results := parseResults() 52 53 switch operation { 54 case encode: 55 if len(results) == 0 { // if no results provided use defaults 56 for i := range carriers { 57 results = append(results, fmt.Sprintf("result%d", i)) 58 } 59 } 60 if len(results) != len(carriers) { 61 fmt.Fprintln(os.Stderr, "Carrier and result files count must be equal when encoding.") 62 os.Exit(1) 63 } 64 if dataFile == nil || *dataFile == "" { 65 fmt.Fprintln(os.Stderr, "Data file must be specified. Use stegify --help for more information.") 66 os.Exit(1) 67 } 68 69 err := steg.MultiCarrierEncodeByFileNames(carriers, *dataFile, results) 70 if err != nil { 71 fmt.Fprintln(os.Stderr, err) 72 os.Exit(1) 73 } 74 case decode: 75 if len(results) == 0 { // if no result provided use default 76 results = append(results, "result") 77 } 78 if len(results) != 1 { 79 fmt.Fprintln(os.Stderr, "Only one result file expected.") 80 os.Exit(1) 81 } 82 err := steg.MultiCarrierDecodeByFileNames(carriers, results[0]) 83 if err != nil { 84 fmt.Fprintln(os.Stderr, err) 85 os.Exit(1) 86 } 87 } 88} 89 90func parseOperation() string { 91 if len(os.Args) < 2 { 92 fmt.Fprintln(os.Stderr, "Operation must be specified [encode/decode]. Use stegify --help for more information.") 93 os.Exit(1) 94 } 95 operation := os.Args[1] 96 if operation != encode && operation != decode { 97 helpFlags := map[string]bool{ 98 "--help": true, 99 "-help": true, 100 "--h": true, 101 "-h": true, 102 } 103 if helpFlags[operation] { 104 flag.Parse() 105 os.Exit(0) 106 } 107 fmt.Fprintf(os.Stderr, "Unsupported operation: %s. Only [encode/decode] operations are supported.\n Use stegify --help for more information.", operation) 108 os.Exit(1) 109 } 110 111 os.Args = append(os.Args[:1], os.Args[2:]...) // needed because go flags implementation stop parsing after first non-flag argument 112 return operation 113} 114 115func parseCarriers() []string { 116 carriers := make([]string, 0) 117 if len(carrierFilesSlice) != 0 { 118 carriers = append(carriers, carrierFilesSlice...) 119 } 120 121 if len(*carrierFiles) != 0 { 122 carriers = append(carriers, strings.Split(*carrierFiles, " ")...) 123 } 124 125 if len(carriers) == 0 { 126 fmt.Fprintln(os.Stderr, "Carrier file must be specified. Use stegify --help for more information.") 127 os.Exit(1) 128 } 129 130 return carriers 131} 132 133func parseResults() []string { 134 results := make([]string, 0) 135 if len(resultFilesSlice) != 0 { 136 results = append(results, resultFilesSlice...) 137 } 138 139 if len(*resultFiles) != 0 { 140 results = append(results, strings.Split(*resultFiles, " ")...) 141 } 142 143 return results 144} 145