Browse Source

string utils; cli

develop
Robin Thoni 7 years ago
parent
commit
c843a32aed

+ 17
- 0
CMakeLists.txt View File

@@ -1,5 +1,22 @@
1 1
 cmake_minimum_required(VERSION 2.8)
2 2
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
3
+
4
+execute_process(COMMAND git log --pretty=format:%h -n 1
5
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
6
+        OUTPUT_VARIABLE GIT_SHA1)
7
+
8
+execute_process(COMMAND git symbolic-ref -q --short HEAD
9
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
10
+        OUTPUT_VARIABLE GIT_REF_NAME)
11
+if ("${GIT_REF_NAME}" EQUAL "")
12
+    execute_process(COMMAND git describe --tags --exact-match
13
+            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
14
+            OUTPUT_VARIABLE GIT_REF_NAME)
15
+endif()
16
+string(STRIP "${GIT_REF_NAME}" GIT_REF_NAME)
17
+string(STRIP "${GIT_SHA1}" GIT_SHA1)
18
+add_definitions(-DGIT_SHA1=${GIT_SHA1} -DGIT_REF_NAME=${GIT_REF_NAME})
19
+
3 20
 set(PROJECT_NAME mifare-tools)
4 21
 project(${PROJECT_NAME})
5 22
 find_package(GTest)

+ 4
- 2
cli/DBO/CommandLineOption.cpp View File

@@ -4,8 +4,9 @@
4 4
 
5 5
 #include "CommandLineOption.h"
6 6
 
7
-CommandLineOption::CommandLineOption(const std::string &longName, char shortName, const std::string &description,
8
-                                     const std::string &valueName, const std::string &defaultValue)
7
+CommandLineOption::CommandLineOption(CommandLineParser* parser, const std::string &longName, char shortName,
8
+                                     const std::string &description, const std::string &valueName,
9
+                                     const std::string &defaultValue)
9 10
     : _longName(longName)
10 11
     , _shortName(shortName)
11 12
     , _description(description)
@@ -13,6 +14,7 @@ CommandLineOption::CommandLineOption(const std::string &longName, char shortName
13 14
     , _defaultValue(defaultValue)
14 15
     , _isSet(false)
15 16
 {
17
+    parser->addOption(this);
16 18
 }
17 19
 
18 20
 const std::string &CommandLineOption::getLongName() const

+ 6
- 2
cli/DBO/CommandLineOption.h View File

@@ -7,12 +7,16 @@
7 7
 
8 8
 # include <string>
9 9
 # include <vector>
10
+#include <Interface/CommandLineParser.h>
11
+
12
+class CommandLineParser;
10 13
 
11 14
 class CommandLineOption
12 15
 {
13 16
 public:
14
-    CommandLineOption(const std::string& longName, char shortName, const std::string& description,
15
-                      const std::string& valueName = "", const std::string& defaultValue = "");
17
+    CommandLineOption(CommandLineParser* parser, const std::string& longName, char shortName,
18
+                      const std::string& description, const std::string& valueName = "",
19
+                      const std::string& defaultValue = "");
16 20
 
17 21
     const std::string &getLongName() const;
18 22
 

+ 26
- 2
cli/Interface/CommandLineParser.cpp View File

@@ -60,15 +60,39 @@ void CommandLineParser::addOption(CommandLineOption* opt)
60 60
 int CommandLineParser::showHelp(int status, bool stdErr)
61 61
 {
62 62
     auto& out = stdErr ? std::cerr : std::cout;
63
+    int longestName = 0;
64
+    int longestValue = 0;
65
+    for (auto opt : _options) {
66
+        if (opt->getLongName().length() > longestName) {
67
+            longestName = opt->getLongName().length();
68
+        }
69
+        std::string value = "<" + opt->getValueName();
70
+        if (!opt->getDefaultValue().empty()) {
71
+            value += opt->getDefaultValue();
72
+        }
73
+        value += ">";
74
+        if (value.length() > longestValue) {
75
+            longestValue = value.length();
76
+        }
77
+    }
63 78
     out << "Options:" << std::endl;
64 79
     for (auto opt : _options)
65 80
     {
66 81
         out << "  -" << opt->getShortName() << ", --" << opt->getLongName();
82
+        out << std::string(longestName - opt->getLongName().length() + 2, ' ');
67 83
         if (opt->hasValue())
68 84
         {
69
-            out << " <" << opt->getValueName() << "=" << opt->getDefaultValue() << ">";
85
+            std::string value = "<" + opt->getValueName();
86
+            if (!opt->getDefaultValue().empty()) {
87
+                value += opt->getDefaultValue();
88
+            }
89
+            value += ">";
90
+            out << value << std::string(longestValue - value.length() + 2, ' ');
91
+        }
92
+        else {
93
+            out << std::string(longestValue + 2, ' ');
70 94
         }
71
-        out << " " << opt->getDescription() << std::endl;
95
+        out << opt->getDescription() << std::endl;
72 96
     }
73 97
     return status;
74 98
 }

+ 2
- 0
cli/Interface/CommandLineParser.h View File

@@ -7,6 +7,8 @@
7 7
 
8 8
 # include "../DBO/CommandLineOption.h"
9 9
 
10
+class CommandLineOption;
11
+
10 12
 class CommandLineParser
11 13
 {
12 14
 public:

+ 131
- 23
cli/Interface/MainClass.cpp View File

@@ -4,9 +4,10 @@
4 4
 
5 5
 #include <iostream>
6 6
 #include <sysexits.h>
7
+#include <iomanip>
8
+#include <fstream>
7 9
 #include <DBO/StringUtils.h>
8 10
 #include <Business/FreeFareDeviceBusiness.h>
9
-#include <iomanip>
10 11
 #include "DBO/Result.h"
11 12
 #include "Business/LibNfcBusiness.h"
12 13
 #include "CommandLineParser.h"
@@ -18,9 +19,61 @@ MainClass::MainClass(int argc, char *argv[])
18 19
 {
19 20
 }
20 21
 
22
+#define Q(x) #x
23
+#define QUOTE(x) Q(x)
24
+
25
+#ifndef GIT_SHA1
26
+#define GIT_SHA1 "unknown"
27
+#endif
28
+
29
+#ifndef GIT_REF_NAME
30
+#define GIT_REF_NAME "unknown"
31
+#endif
32
+
21 33
 int MainClass::main()
22 34
 {
23
-    std::cout << "LibNfc version: " << LibNfcBusiness::getVersion() << std::endl;
35
+    CommandLineParser parser(_argc, _argv);
36
+    CommandLineOption optionVersion(&parser, "version", 'v', "Show libnfc and mifare-tools versions");
37
+    CommandLineOption optionHelp(&parser, "help", 'h', "Show this help");
38
+
39
+    CommandLineOption optionDevice(&parser, "device", 'd', "Use the device DEVICE", "DEVICE");
40
+    CommandLineOption optionUid(&parser, "uid", 'u', "Use the UID tag", "UID");
41
+
42
+    CommandLineOption optionKeyFile(&parser, "key-file", 'f', "Path to a file containing keys", "FILE");
43
+
44
+    if (!parser.parse()) {
45
+        return parser.showHelp(EX_USAGE);
46
+    }
47
+    if (optionVersion.isSet()) {
48
+        printVersion();
49
+        return 0;
50
+    }
51
+    if (optionHelp.isSet()) {
52
+        return parser.showHelp(0, false);
53
+    }
54
+
55
+    std::string deviceName = "";
56
+    if (!optionDevice.isSet()) {
57
+        deviceName = optionDevice.getValue();
58
+    }
59
+
60
+    std::string tagUid = "";
61
+    if (!optionUid.isSet()) {
62
+        tagUid = optionUid.getValue();
63
+    }
64
+
65
+    std::vector<std::string> keys;
66
+    if (optionKeyFile.isSet()) {
67
+        for (auto filePath : optionKeyFile.getValues()) {
68
+            auto keysResult = readFile(filePath);
69
+            if (!keysResult) {
70
+                keysResult.print();
71
+                return 1;
72
+            }
73
+            auto fileKeys = keysResult.getData();
74
+            keys.insert(keys.end(), fileKeys.begin(), fileKeys.end());
75
+        }
76
+    }
24 77
 
25 78
     LibNfcBusiness libNfc;
26 79
     auto init = libNfc.init();
@@ -35,18 +88,11 @@ int MainClass::main()
35 88
         return 2;
36 89
     }
37 90
     auto devices = devicesResult.getData();
38
-    if (devices.size() == 0) {
39
-        std::cerr << "No NFC device found" << std::endl;
91
+    std::shared_ptr<NfcDeviceBusiness> device = getDevice(deviceName, devices);
92
+    if (device == 0) {
93
+        std::cerr << "NFC device not found" << std::endl;
40 94
         return 3;
41 95
     }
42
-
43
-    std::cout << "Found " << devices.size() << " devices: " << std::endl;
44
-    for (size_t i = 0; i < devices.size(); ++i) {
45
-        std::cout << devices[i]->getConnStr() << std::endl;
46
-    }
47
-    std::cout << "Using first device" << std::endl;
48
-
49
-    auto device = devices[0];
50 96
     auto open = device->open();
51 97
     if (!open) {
52 98
         open.print();
@@ -66,20 +112,16 @@ int MainClass::main()
66 112
         return 6;
67 113
     }
68 114
 
69
-    std::cout << "Found " << tagsResult.getData().size() << " tags:" << std::endl;
70
-    for (size_t i = 0; i < tagsResult.getData().size(); ++i) {
71
-        auto tag = tagsResult.getData()[i];
72
-        std::cout << "UID: " << tag->getUid() << std::endl;
73
-        std::cout << "Type: " << tag->getType() << std::endl;
115
+    auto tag = getTag(tagUid, tags);
116
+    if (tag == 0) {
117
+        std::cerr << "Tag not found" << std::endl;
118
+        return 6;
74 119
     }
75
-    std::cout << "Using first tag" << std::endl;
76 120
 
77
-    auto tag = tags[0];
78
-
79
-    std::vector<std::string> keys;
121
+//    std::vector<std::string> keys;
80 122
 //    keys.push_back(StringUtils::humanToRaw("8829da9daf76").getData());
81 123
 //    keys.push_back(StringUtils::humanToRaw("ffffffffffff").getData());
82
-    keys.push_back(StringUtils::humanToRaw("484558414354").getData());
124
+//    keys.push_back(StringUtils::humanToRaw("484558414354").getData());
83 125
 
84 126
     int res = dump(tag, keys);
85 127
 //    int res = mapKeys(tag, keys);
@@ -169,5 +211,71 @@ void MainClass::printTrailerAccessBits(const AccessBitsDbo &accessBits)
169 211
 
170 212
 void MainClass::printPercent(int done, int total)
171 213
 {
172
-    std::cout << "\r" << std::fixed << std::setprecision(1) <<  ((float)done / (float)total * 100.0) << "%" << std::flush;
214
+    std::cout << "\r\033[2K" << std::fixed << std::setprecision(1) << ((float)done / (float)total * 100.0) << "%" << std::flush;
215
+}
216
+
217
+void MainClass::printVersion() const
218
+{
219
+    std::cout << "LibNfc version: " << LibNfcBusiness::getVersion() << std::endl;
220
+    std::cout << "Mifare-tools version: " << QUOTE(GIT_REF_NAME) << "-" << QUOTE(GIT_SHA1) << std::endl;
221
+}
222
+
223
+std::shared_ptr<NfcDeviceBusiness> MainClass::getDevice(const std::string &deviceName, std::vector<std::shared_ptr<NfcDeviceBusiness>> devices)
224
+{
225
+    if (deviceName.empty()) {
226
+        if (devices.size() > 0) {
227
+            return devices[0];
228
+        }
229
+    }
230
+    else {
231
+        for (auto d : devices) {
232
+            if (d->getConnStr() == deviceName) {
233
+                return d;
234
+            }
235
+        }
236
+    }
237
+    return 0;
238
+}
239
+
240
+std::shared_ptr<FreeFareTagBusiness> MainClass::getTag(const std::string &tagUid,
241
+                                                       std::vector<std::shared_ptr<FreeFareTagBusiness>> tags)
242
+{
243
+    if (tagUid.empty()) {
244
+        if (tags.size() > 0) {
245
+            return tags[0];
246
+        }
247
+    }
248
+    else {
249
+        for (auto t : tags) {
250
+            if (t->getUid() == tagUid) {
251
+                return t;
252
+            }
253
+        }
254
+    }
255
+    return 0;
256
+}
257
+
258
+Result<std::vector<std::string>> MainClass::readFile(const std::string &filePath)
259
+{
260
+    std::vector<std::string> lines;
261
+    std::ifstream fileInput(filePath);
262
+    if (fileInput) {
263
+        while (!fileInput.eof()) {
264
+            std::string line;
265
+            std::getline(fileInput, line);
266
+            line = StringUtils::removeSpaces(line);
267
+            if (line.compare(0, 1, "#") != 0 && line.compare(0, 1, "+") != 0) {
268
+                auto keyResult = StringUtils::humanToRaw(line);
269
+                if (!keyResult) {
270
+                    return Result<std::vector<std::string>>::error("Invalid file data");
271
+                }
272
+                line = keyResult.getData();
273
+                lines.push_back(line);
274
+            }
275
+        }
276
+    }
277
+    else {
278
+        return Result<std::vector<std::string>>::error("Failed to open file: " + std::string(strerror(errno)));
279
+    }
280
+    return Result<std::vector<std::string>>::ok(lines);
173 281
 }

+ 9
- 0
cli/Interface/MainClass.h View File

@@ -7,6 +7,7 @@
7 7
 
8 8
 #include <memory>
9 9
 #include <Business/FreeFareTagBusiness.h>
10
+#include <Business/NfcDeviceBusiness.h>
10 11
 
11 12
 class MainClass {
12 13
 public:
@@ -14,14 +15,22 @@ public:
14 15
 
15 16
     int main();
16 17
 
18
+    std::shared_ptr<NfcDeviceBusiness> getDevice(const std::string& deviceName, std::vector<std::shared_ptr<NfcDeviceBusiness>> devices);
19
+
20
+    std::shared_ptr<FreeFareTagBusiness> getTag(const std::string& tagUid, std::vector<std::shared_ptr<FreeFareTagBusiness>> tags);
21
+
17 22
     int mapKeys(std::shared_ptr<FreeFareTagBusiness> tag, std::vector<std::string> keys);
18 23
 
19 24
     int dump(std::shared_ptr<FreeFareTagBusiness> tag, std::vector<std::string> keys);
20 25
 
26
+    Result<std::vector<std::string>> readFile(const std::string& filePath);
27
+
21 28
     void printBlockAccessBits(const AccessBitsDbo& accessBits, int block);
22 29
 
23 30
     void printTrailerAccessBits(const AccessBitsDbo& accessBits);
24 31
 
32
+    void printVersion() const;
33
+
25 34
     static void printPercent(int done, int total);
26 35
 
27 36
 private:

+ 27
- 0
src/DBO/StringUtils.cpp View File

@@ -2,6 +2,7 @@
2 2
 // Created by robin on 6/20/16.
3 3
 //
4 4
 
5
+#include <algorithm>
5 6
 #include "StringUtils.h"
6 7
 
7 8
 const std::string StringUtils::hex = "0123456789abcdef";
@@ -122,4 +123,30 @@ std::string StringUtils::ensureSize(const std::string &data, int size)
122 123
     }
123 124
 }
124 125
 
126
+std::string StringUtils::ltrim(const std::string& s)
127
+{
128
+    std::string data = s;
129
+    data.erase(data.begin(), std::find_if(data.begin(), data.end(),
130
+                                    std::not1(std::ptr_fun<int, int>(std::isspace))));
131
+    return data;
132
+}
133
+
134
+std::string StringUtils::rtrim(const std::string& s)
135
+{
136
+    std::string data = s;
137
+    data.erase(std::find_if(data.rbegin(), data.rend(),
138
+                         std::not1(std::ptr_fun<int, int>(std::isspace))).base(), data.end());
139
+    return data;
140
+}
125 141
 
142
+std::string StringUtils::trim(const std::string& s)
143
+{
144
+    return ltrim(rtrim(s));
145
+}
146
+
147
+std::string StringUtils::removeSpaces(const std::string &s)
148
+{
149
+    std::string data = s;
150
+    data.erase(std::remove_if(data.begin(), data.end(), std::ptr_fun<int, int>(std::isspace)), data.end());
151
+    return data;
152
+}

+ 5
- 0
src/DBO/StringUtils.h View File

@@ -33,6 +33,11 @@ public:
33 33
     static char toUpper(char c);
34 34
 
35 35
     static std::string ensureSize(const std::string& data, int size);
36
+
37
+    static std::string ltrim(const std::string& s);
38
+    static std::string rtrim(const std::string& s);
39
+    static std::string trim(const std::string& s);
40
+    static std::string removeSpaces(const std::string& s);
36 41
 };
37 42
 
38 43
 

+ 32
- 0
tests/test-main.cpp View File

@@ -100,6 +100,38 @@ TEST(StringUtils, ensureSize)
100 100
   ASSERT_EQ(StringUtils::ensureSize("test", 5), std::string({'t', 'e', 's', 't', '\0'}));
101 101
 }
102 102
 
103
+TEST(StringUtils, ltrim)
104
+{
105
+  ASSERT_EQ(StringUtils::ltrim("  \n 42"), "42");
106
+  ASSERT_EQ(StringUtils::ltrim("  \n 42 \n"), "42 \n");
107
+  ASSERT_EQ(StringUtils::ltrim("42  \n "), "42  \n ");
108
+  ASSERT_EQ(StringUtils::ltrim(" 42 \n 42  \n "), "42 \n 42  \n ");
109
+}
110
+
111
+TEST(StringUtils, rtrim)
112
+{
113
+  ASSERT_EQ(StringUtils::rtrim("  \n 42"), "  \n 42");
114
+  ASSERT_EQ(StringUtils::rtrim("  \n 42 \n"), "  \n 42");
115
+  ASSERT_EQ(StringUtils::rtrim("42  \n "), "42");
116
+  ASSERT_EQ(StringUtils::rtrim(" 42 \n 42  \n "), " 42 \n 42");
117
+}
118
+
119
+TEST(StringUtils, trim)
120
+{
121
+  ASSERT_EQ(StringUtils::trim("  \n 42"), "42");
122
+  ASSERT_EQ(StringUtils::trim("  \n 42 \n"), "42");
123
+  ASSERT_EQ(StringUtils::trim("42  \n "), "42");
124
+  ASSERT_EQ(StringUtils::trim(" 42 \n 42  \n "), "42 \n 42");
125
+}
126
+
127
+TEST(StringUtils, removeSpaces)
128
+{
129
+  ASSERT_EQ(StringUtils::removeSpaces("  \n 42"), "42");
130
+  ASSERT_EQ(StringUtils::removeSpaces("  \n 42 \n"), "42");
131
+  ASSERT_EQ(StringUtils::removeSpaces("42  \n "), "42");
132
+  ASSERT_EQ(StringUtils::removeSpaces(" 42 \n 42  \n "), "4242");
133
+}
134
+
103 135
 TEST(ArrayUtils, getArrayBitimple)
104 136
 {
105 137
   const unsigned char buf[] = {0x04};

Loading…
Cancel
Save