diff options
Diffstat (limited to 'tools/idevicescreenshot.c')
-rw-r--r-- | tools/idevicescreenshot.c | 228 |
1 files changed, 117 insertions, 111 deletions
diff --git a/tools/idevicescreenshot.c b/tools/idevicescreenshot.c index 9b1ffa3..0e694c7 100644 --- a/tools/idevicescreenshot.c +++ b/tools/idevicescreenshot.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <stdio.h> | 28 | #include <stdio.h> |
29 | #include <string.h> | 29 | #include <string.h> |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | #include <getopt.h> | ||
31 | #include <errno.h> | 32 | #include <errno.h> |
32 | #include <time.h> | 33 | #include <time.h> |
33 | #include <unistd.h> | 34 | #include <unistd.h> |
@@ -39,8 +40,86 @@ | |||
39 | #include <libimobiledevice/lockdown.h> | 40 | #include <libimobiledevice/lockdown.h> |
40 | #include <libimobiledevice/screenshotr.h> | 41 | #include <libimobiledevice/screenshotr.h> |
41 | 42 | ||
42 | void get_image_filename(char *imgdata, char **filename); | 43 | static void get_image_filename(char *imgdata, char **filename) |
43 | void print_usage(int argc, char **argv); | 44 | { |
45 | // If the provided filename already has an extension, use it as is. | ||
46 | if (*filename) { | ||
47 | char *last_dot = strrchr(*filename, '.'); | ||
48 | if (last_dot && !strchr(last_dot, '/')) { | ||
49 | return; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | // Find the appropriate file extension for the filename. | ||
54 | const char *fileext = NULL; | ||
55 | if (memcmp(imgdata, "\x89PNG", 4) == 0) { | ||
56 | fileext = ".png"; | ||
57 | } else if (memcmp(imgdata, "MM\x00*", 4) == 0) { | ||
58 | fileext = ".tiff"; | ||
59 | } else { | ||
60 | printf("WARNING: screenshot data has unexpected image format.\n"); | ||
61 | fileext = ".dat"; | ||
62 | } | ||
63 | |||
64 | // If a filename without an extension is provided, append the extension. | ||
65 | // Otherwise, generate a filename based on the current time. | ||
66 | char *basename = NULL; | ||
67 | if (*filename) { | ||
68 | basename = (char*)malloc(strlen(*filename) + 1); | ||
69 | strcpy(basename, *filename); | ||
70 | free(*filename); | ||
71 | *filename = NULL; | ||
72 | } else { | ||
73 | time_t now = time(NULL); | ||
74 | basename = (char*)malloc(32); | ||
75 | strftime(basename, 31, "screenshot-%Y-%m-%d-%H-%M-%S", gmtime(&now)); | ||
76 | } | ||
77 | |||
78 | // Ensure the filename is unique on disk. | ||
79 | char *unique_filename = (char*)malloc(strlen(basename) + strlen(fileext) + 7); | ||
80 | sprintf(unique_filename, "%s%s", basename, fileext); | ||
81 | int i; | ||
82 | for (i = 2; i < (1 << 16); i++) { | ||
83 | if (access(unique_filename, F_OK) == -1) { | ||
84 | *filename = unique_filename; | ||
85 | break; | ||
86 | } | ||
87 | sprintf(unique_filename, "%s-%d%s", basename, i, fileext); | ||
88 | } | ||
89 | if (!*filename) { | ||
90 | free(unique_filename); | ||
91 | } | ||
92 | free(basename); | ||
93 | } | ||
94 | |||
95 | static void print_usage(int argc, char **argv, int is_error) | ||
96 | { | ||
97 | char *name = strrchr(argv[0], '/'); | ||
98 | fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] [FILE]\n", (name ? name + 1: argv[0])); | ||
99 | fprintf(is_error ? stderr : stdout, | ||
100 | "\n" | ||
101 | "Gets a screenshot from a connected device.\n" | ||
102 | "\n" | ||
103 | "The image is in PNG format for iOS 9+ and otherwise in TIFF format.\n" | ||
104 | "The screenshot is saved as an image with the given FILE name.\n" | ||
105 | "If FILE has no extension, FILE will be a prefix of the saved filename.\n" | ||
106 | "If FILE is not specified, \"screenshot-DATE\", will be used as a prefix\n" | ||
107 | "of the filename, e.g.:\n" | ||
108 | " ./screenshot-2013-12-31-23-59-59.tiff\n" | ||
109 | "\n" | ||
110 | "NOTE: A mounted developer disk image is required on the device, otherwise\n" | ||
111 | "the screenshotr service is not available.\n" | ||
112 | "\n" | ||
113 | " -u, --udid UDID target specific device by UDID\n" | ||
114 | " -n, --network connect to network device\n" | ||
115 | " -d, --debug enable communication debugging\n" | ||
116 | " -h, --help prints usage information\n" | ||
117 | " -v, --version prints version information\n" | ||
118 | "\n" | ||
119 | "Homepage: <" PACKAGE_URL ">\n" | ||
120 | "Bug Reports: <" PACKAGE_BUGREPORT ">\n" | ||
121 | ); | ||
122 | } | ||
44 | 123 | ||
45 | int main(int argc, char **argv) | 124 | int main(int argc, char **argv) |
46 | { | 125 | { |
@@ -50,50 +129,58 @@ int main(int argc, char **argv) | |||
50 | screenshotr_client_t shotr = NULL; | 129 | screenshotr_client_t shotr = NULL; |
51 | lockdownd_service_descriptor_t service = NULL; | 130 | lockdownd_service_descriptor_t service = NULL; |
52 | int result = -1; | 131 | int result = -1; |
53 | int i; | ||
54 | const char *udid = NULL; | 132 | const char *udid = NULL; |
55 | int use_network = 0; | 133 | int use_network = 0; |
56 | char *filename = NULL; | 134 | char *filename = NULL; |
135 | int c = 0; | ||
136 | const struct option longopts[] = { | ||
137 | { "debug", no_argument, NULL, 'd' }, | ||
138 | { "help", no_argument, NULL, 'h' }, | ||
139 | { "udid", required_argument, NULL, 'u' }, | ||
140 | { "network", no_argument, NULL, 'n' }, | ||
141 | { "version", no_argument, NULL, 'v' }, | ||
142 | { NULL, 0, NULL, 0} | ||
143 | }; | ||
57 | 144 | ||
58 | #ifndef WIN32 | 145 | #ifndef WIN32 |
59 | signal(SIGPIPE, SIG_IGN); | 146 | signal(SIGPIPE, SIG_IGN); |
60 | #endif | 147 | #endif |
61 | /* parse cmdline args */ | 148 | /* parse cmdline args */ |
62 | for (i = 1; i < argc; i++) { | 149 | |
63 | if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { | 150 | /* parse cmdline arguments */ |
151 | while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { | ||
152 | switch (c) { | ||
153 | case 'd': | ||
64 | idevice_set_debug_level(1); | 154 | idevice_set_debug_level(1); |
65 | continue; | 155 | break; |
66 | } | 156 | case 'u': |
67 | else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { | 157 | if (!*optarg) { |
68 | i++; | 158 | fprintf(stderr, "ERROR: UDID argument must not be empty!\n"); |
69 | if (!argv[i] || !*argv[i]) { | 159 | print_usage(argc, argv, 1); |
70 | print_usage(argc, argv); | 160 | return 2; |
71 | return 0; | ||
72 | } | 161 | } |
73 | udid = argv[i]; | 162 | udid = optarg; |
74 | continue; | 163 | break; |
75 | } | 164 | case 'n': |
76 | else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--network")) { | ||
77 | use_network = 1; | 165 | use_network = 1; |
78 | continue; | 166 | break; |
79 | } | 167 | case 'h': |
80 | else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { | 168 | print_usage(argc, argv, 0); |
81 | print_usage(argc, argv); | ||
82 | return 0; | 169 | return 0; |
83 | } | 170 | case 'v': |
84 | else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { | ||
85 | printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); | 171 | printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); |
86 | return 0; | 172 | return 0; |
87 | } | 173 | default: |
88 | else if (argv[i][0] != '-' && !filename) { | 174 | print_usage(argc, argv, 1); |
89 | filename = strdup(argv[i]); | 175 | return 2; |
90 | continue; | ||
91 | } | ||
92 | else { | ||
93 | print_usage(argc, argv); | ||
94 | return 0; | ||
95 | } | 176 | } |
96 | } | 177 | } |
178 | argc -= optind; | ||
179 | argv += optind; | ||
180 | |||
181 | if (argv[0]) { | ||
182 | filename = strdup(argv[0]); | ||
183 | } | ||
97 | 184 | ||
98 | if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) { | 185 | if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) { |
99 | if (udid) { | 186 | if (udid) { |
@@ -153,84 +240,3 @@ int main(int argc, char **argv) | |||
153 | 240 | ||
154 | return result; | 241 | return result; |
155 | } | 242 | } |
156 | |||
157 | void get_image_filename(char *imgdata, char **filename) | ||
158 | { | ||
159 | // If the provided filename already has an extension, use it as is. | ||
160 | if (*filename) { | ||
161 | char *last_dot = strrchr(*filename, '.'); | ||
162 | if (last_dot && !strchr(last_dot, '/')) { | ||
163 | return; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | // Find the appropriate file extension for the filename. | ||
168 | const char *fileext = NULL; | ||
169 | if (memcmp(imgdata, "\x89PNG", 4) == 0) { | ||
170 | fileext = ".png"; | ||
171 | } else if (memcmp(imgdata, "MM\x00*", 4) == 0) { | ||
172 | fileext = ".tiff"; | ||
173 | } else { | ||
174 | printf("WARNING: screenshot data has unexpected image format.\n"); | ||
175 | fileext = ".dat"; | ||
176 | } | ||
177 | |||
178 | // If a filename without an extension is provided, append the extension. | ||
179 | // Otherwise, generate a filename based on the current time. | ||
180 | char *basename = NULL; | ||
181 | if (*filename) { | ||
182 | basename = (char*)malloc(strlen(*filename) + 1); | ||
183 | strcpy(basename, *filename); | ||
184 | free(*filename); | ||
185 | *filename = NULL; | ||
186 | } else { | ||
187 | time_t now = time(NULL); | ||
188 | basename = (char*)malloc(32); | ||
189 | strftime(basename, 31, "screenshot-%Y-%m-%d-%H-%M-%S", gmtime(&now)); | ||
190 | } | ||
191 | |||
192 | // Ensure the filename is unique on disk. | ||
193 | char *unique_filename = (char*)malloc(strlen(basename) + strlen(fileext) + 7); | ||
194 | sprintf(unique_filename, "%s%s", basename, fileext); | ||
195 | int i; | ||
196 | for (i = 2; i < (1 << 16); i++) { | ||
197 | if (access(unique_filename, F_OK) == -1) { | ||
198 | *filename = unique_filename; | ||
199 | break; | ||
200 | } | ||
201 | sprintf(unique_filename, "%s-%d%s", basename, i, fileext); | ||
202 | } | ||
203 | if (!*filename) { | ||
204 | free(unique_filename); | ||
205 | } | ||
206 | free(basename); | ||
207 | } | ||
208 | |||
209 | void print_usage(int argc, char **argv) | ||
210 | { | ||
211 | char *name = NULL; | ||
212 | |||
213 | name = strrchr(argv[0], '/'); | ||
214 | printf("Usage: %s [OPTIONS] [FILE]\n", (name ? name + 1: argv[0])); | ||
215 | printf("\n"); | ||
216 | printf("Gets a screenshot from a connected device.\n"); | ||
217 | printf("\n"); | ||
218 | printf("The image is in PNG format for iOS 9+ and otherwise in TIFF format.\n"); | ||
219 | printf("The screenshot is saved as an image with the given FILE name.\n"); | ||
220 | printf("If FILE has no extension, FILE will be a prefix of the saved filename.\n"); | ||
221 | printf("If FILE is not specified, \"screenshot-DATE\", will be used as a prefix\n"); | ||
222 | printf("of the filename, e.g.:\n"); | ||
223 | printf(" ./screenshot-2013-12-31-23-59-59.tiff\n"); | ||
224 | printf("\n"); | ||
225 | printf("NOTE: A mounted developer disk image is required on the device, otherwise\n"); | ||
226 | printf("the screenshotr service is not available.\n"); | ||
227 | printf("\n"); | ||
228 | printf(" -u, --udid UDID\ttarget specific device by UDID\n"); | ||
229 | printf(" -n, --network\t\tconnect to network device\n"); | ||
230 | printf(" -d, --debug\t\tenable communication debugging\n"); | ||
231 | printf(" -h, --help\t\tprints usage information\n"); | ||
232 | printf(" -v, --version\t\tprints version information\n"); | ||
233 | printf("\n"); | ||
234 | printf("Homepage: <" PACKAGE_URL ">\n"); | ||
235 | printf("Bug Reports: <" PACKAGE_BUGREPORT ">\n"); | ||
236 | } | ||