1 // Copyright 2020 Michael Reilly (mreilly@resiliware.com).
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions
5 // are met:
6 // 1. Redistributions of source code must retain the above copyright
7 //    notice, this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright
9 //    notice, this list of conditions and the following disclaimer in the
10 //    documentation and/or other materials provided with the distribution.
11 // 3. Neither the names of the copyright holders nor the names of the
12 //    contributors may be used to endorse or promote products derived from
13 //    this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
19 // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #ifndef _HEXPEEK_H_
28 #define _HEXPEEK_H_
29 
30 #define _FILE_OFFSET_BITS 64
31 
32 #include <resiliware_util.h>
33 
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <stdbool.h>
37 #include <inttypes.h>
38 #include <ctype.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 
43 //----------------------------- Build Parameters -----------------------------//
44 
45 // WARNING: hexpeek is a trademark. Modified redistributions under the same
46 // name should uncomment HEXPEEK_MODIFIED below. Feel free to add more
47 // information such as "modified by X" or "modified for Y". See the root
48 // project directory README for more information.
49 #define HEXPEEK_PROGRAM_NAME    "hexpeek"
50 //#define HEXPEEK_MODIFIED        " [modified]"
51 #define HEXPEEK_PROGRAM_VERSION "1.0.20200804"
52 #define HEXPEEK_URL             "https://www.hexpeek.com"
53 #define HEXPEEK_EMAIL           "hexpeek@hexpeek.com"
54 
55 //#define HEXPEEK_BETA            Set by Makefile
56 //#define HEXPEEK_EDITABLE_CONSOLE
57 
58 #define HEXPEEK_TRACE
59 //#define HEXPEEK_TRACE_EXTENDED
60 #define HEXPEEK_UNIQUE_INFILES
61 //#define HEXPEEK_ALWAYS_FILECPY
62 //#define HEXPEEK_PLUGINS
63 
64 //---------------------------- Basic Definitions -----------------------------//
65 
66 #define PRGNM HEXPEEK_PROGRAM_NAME
67 #define viwNM "hexview"
68 #define DmpNM "hexDump"
69 #define pckNM "hexpack"
70 #define dffNM "hexdiff"
71 
72 #define PAGESZ      0x1000
73 #define BUFSZ      0x10000
74 #define SRCHSZ       BUFSZ
75 #define MAXW_LINE    BUFSZ
76 #define MAXW_GROUP   BUFSZ
77 
78 #define DEF_SCALAR_BASE  0x10
79 
80 #define MAX_INFILES 2
81 
82 #define BACKUP_FILE_COUNT 2
83 
84 #define PERM (S_IRUSR | S_IWUSR)
85 
86 #define TERMINAL_WIDTH 80
87 
88 //------------------------------- Return Codes -------------------------------//
89 
90 #define RC_NIL     -1
91 #define RC_OK       0
92 #define RC_DIFF     1
93 #define RC_DONE     2
94 #define RC_UNSPEC   3 // any function that returns this has a bug
95 #define RC_USER     4
96 #define RC_CRIT     5
97 
98 #define checkrc(r)  if((r) != RC_OK) goto end;
99 
100 //--------------------------- Numeric Format Modes ---------------------------//
101 
102 #define MODE_HEX      0
103 #define MODE_BITS     1
104 #define MODE_COUNT    2
105 
106 #define HEX_CHCNT     2
107 #define BITS_CHCNT    8
108 #define MODE_CHCNT(m) ((m) ? BITS_CHCNT : HEX_CHCNT)
109 #define DISP_CHCNT    MODE_CHCNT(Params.disp_mode)
110 
111 //----------------------------- Command Indices ------------------------------//
112 
113 #define CMD_NONE        0
114 #define CMD_QUIT        1
115 #define CMD_STOP        2
116 #define CMD_HELP        3
117 #define CMD_FILES       4
118 #define CMD_RESET       5
119 #define CMD_SETTINGS    6
120 #define CMD_ENDIAN      7
121 #define CMD_HEX         8
122 #define CMD_BITS        9
123 #define CMD_RLEN       10
124 #define CMD_SLEN       11
125 #define CMD_LINE       12
126 #define CMD_COLS       13
127 #define CMD_GROUP      14
128 #define CMD_MARGIN     15
129 #define CMD_SCALAR     16
130 #define CMD_PREFIX     17
131 #define CMD_AUTOSKIP   18
132 #define CMD_DIFFSKIP   19
133 #define CMD_TEXT       20
134 #define CMD_RULER      21
135 #define CMD_NUMERIC    22
136 #define CMD_PRINT      23
137 #define CMD_OFFSET     24
138 #define CMD_SEARCH     25
139 #define CMD_DIFF       26
140 #define CMD_REPLACE    27
141 #define CMD_INSERT     28
142 #define CMD_KILL       29
143 #define CMD_OPS        30
144 #define CMD_UNDO       31
145 #define CMD_MIN        CMD_QUIT
146 #define CMD_MAX        CMD_UNDO
147 
148 //----------------------------- Type Definitions -----------------------------//
149 
150 typedef int rc_t;
151 #define TRC_rc "%d"
152 
153 typedef off_t hoff_t;
154 
155 #define HOFF_NIL -0x2F46 // little endian 2's complement looks like bad0ffff
156 #define HOFF_HEX_FULL_WIDTH 0x10
157 #define HOFF_HEX_DEFAULT_WIDTH HOFF_HEX_FULL_WIDTH
158 
159 // Indirection for platforms where printf("%jX") is not recognized
160 #define PRI_hxpkint      "X" "%!!hxpknum"
161 #define PRI_hxpkmax  PRIXMAX "%!!hxpknum"                  // @!!X_IN_PRIXMAX
162 
163 #define FORMAT_HOFF(n, x) \
164     ((n) < 0 ? "-" : ""), (x), ((uintmax_t)(((n) < 0) ? -(n) : (n)))
165 #define HoffPrefix (Params.print_prefix ? "0x" : "")
166 #define PRI_hoff "%s%s%" PRI_hxpkmax
167 #define prihoff(n) FORMAT_HOFF(n, HoffPrefix)
168 #define prihcnt(n) FORMAT_HOFF(n, HoffPrefix), ((n) == 1 ? "" : "s")
169 #define TRC_hoff "%s%s%" PRIXMAX
170 #define trchoff(n) FORMAT_HOFF(n, "0x")
171 
172 typedef struct
173 {
174     char *path;
175     char *name_mal;
176     int open_flags;
177     int fd;
178     hoff_t at;
179     hoff_t last_at;
180     hoff_t track;
181     bool created;
182     uint64_t opcnt;
183     char *bk_path_mal[BACKUP_FILE_COUNT];
184     char *bk_name_mal[BACKUP_FILE_COUNT];
185     int bk_fds[BACKUP_FILE_COUNT];
186 } FileAttr;
187 
188 typedef struct
189 {
190     int scalar_base;
191     int disp_mode;
192     int hexlower;
193     hoff_t mode_print_defs[MODE_COUNT];
194     hoff_t mode_search_defs[MODE_COUNT];
195     hoff_t mode_lines[MODE_COUNT];
196     hoff_t mode_groups[MODE_COUNT];
197     bool endian_big;
198     int margin;
199     int autoskip;
200     bool diffskip;
201     char const *line_term;
202     char const *group_pre[2];
203     char const *group_term;
204     int print_text;
205     int text_encoding;
206     bool ruler;
207     bool print_prefix;
208     bool allow_ik;
209     bool infer;
210     bool tolerate_eof;
211     bool assume_unique_infiles;
212     int assume_ttys;
213     bool recover_interactive;
214     bool recover_auto;
215     long backup_depth;
216     bool backup_sync;
217     int fail_strict;
218     int editable_console;
219     char *command;
220     bool do_pack;
221     FileAttr infiles[MAX_INFILES];
222     FILE *trace_fp;
223 } Settings;
224 
225 void Settings_init(Settings *st);
226 
227 #define FILE_INDEX_NIL   -1
228 #define FILE_INDEX_LATER -2
229 
230 typedef struct
231 {
232     int fi; // index to Params.infiles[]
233     hoff_t start;
234     hoff_t len;
235     bool tolerate_eof;
236 } FileZone;
237 
238 void FileZone_init(FileZone *zone);
239 
240 typedef struct
241 {
242     struct
243     {
244         hoff_t sz;
245         hoff_t count;
246         uint8_t *octets_mal;
247         uint8_t *masks_mal;
248     } mem;
249     FileZone fz;
250 } ConvertedText;
251 
252 void ConvertedText_init(ConvertedText *converted_text);
253 
254 typedef struct
255 {
256     char const *origcmd;
257     int cmd;
258     int subtype; // only used by shared commands
259     FileZone fz;
260     bool incr_pre;
261     bool incr_post;
262     bool print_off;
263     bool print_verbose;
264     bool diff_srch;
265     char const *arg_t;
266     ConvertedText arg_cv;
267 } ParsedCommand;
268 
269 void ParsedCommand_init(ParsedCommand *parsed_command);
270 
271 //------------------------------ Constant Data -------------------------------//
272 
273 extern char const VersionShort[];
274 extern char const VersionLong[];
275 
276 extern char const LicenseString[];
277 extern char const AuthorshipString[];
278 extern char const UsageStringShort[];
279 extern char const UsageStringExtended[];
280 
281 extern char const HelpCmdList[];
282 extern char const HelpCmdHdr[];
283 extern char const * HelpText[];
284 extern char const HelpOther[];
285 
286 #define OCTET_COUNT 0x100
287 
288 extern char const *BinLookup_hexl[OCTET_COUNT];
289 
290 extern char const *BinLookup_hexu[OCTET_COUNT];
291 
292 extern char const *BinLookup_bits[OCTET_COUNT];
293 
294 #define CODEPAGE_ASCII  1
295 #define CODEPAGE_EBCDIC 2
296 #define CODEPAGE_NIL    3
297 
298 char *getEncoded(int codepage, uint8_t *in, size_t len, char *out);
299 
300 char const *getEncodedVerbose(int codepage, uint8_t data);
301 
302 char const *encodingName(int codepage);
303 
304 #define EofErrString "unexpectedly reached end of file while reading from %s\n"
305 
306 //----------------- Global Variables and Run-Time Constants ------------------//
307 
308 extern hoff_t HOFF_MAX;
309 
310 #define MASK_COUNT (sizeof(uintmax_t) * HEX_CHCNT + 1)
311 
312 extern uintmax_t Masks[MASK_COUNT];
313 
314 extern uint8_t CharLookup[OCTET_COUNT];
315 
316 extern char *GeneratedCommand_mal;
317 
318 extern char *CleanString_mal;
319 
320 extern char *LnInput_mal;
321 
322 extern size_t LnInputSz;
323 
324 extern bool BackupUnlinkAllowed;
325 
326 extern Settings Params;
327 
328 void initialize();
329 
330 void cleanup();
331 
332 //-------------------------------- Shortcuts ---------------------------------//
333 
334 #define DT_PATH(i)     Params.infiles[i].path
335 #define DT_NAME(i)     Params.infiles[i].name_mal
336 #define DT_MODE(i)     Params.infiles[i].open_flags
337 #define DT_FD(i)       Params.infiles[i].fd
338 #define DT_AT(i)       Params.infiles[i].at
339 #define DT_OPCNT(i)    Params.infiles[i].opcnt
340 
341 #define BK_PATH(i, j)  Params.infiles[i].bk_path_mal[j]
342 #define BK_NAME(i, j)  Params.infiles[i].bk_name_mal[j]
343 #define BK_FD(i, j)    Params.infiles[i].bk_fds[j]
344 
345 #define DispMode       Params.disp_mode
346 #define DispPrDef      Params.mode_print_defs[Params.disp_mode]
347 #define DispSrchDef    Params.mode_search_defs[Params.disp_mode]
348 #define DispLine       Params.mode_lines[Params.disp_mode]
349 #define DispGroup      Params.mode_groups[Params.disp_mode]
350 #define BackupDepth    Params.backup_depth
351 
352 //---------------------------- Output Formatting -----------------------------//
353 
354 #define LineTerm       Params.line_term
355 #define GroupPre(li)   ((li) ? Params.group_pre[1] : Params.group_pre[0])
356 #define GroupTerm      Params.group_term
357 
358 #define PromptString   "> "
359 #define MarginPost     ": "
360 #define GroupFmtGroup  "%_g"
361 #define GroupFmtLiTern "%_l?"
362 #define DiffSplit      "|"
363 #define AutoskipOutput "*"
364 
365 //--------------------------------- Tracing ----------------------------------//
366 
367 #ifdef HEXPEEK_TRACE
368     #define trace(...)      tracef(Params.trace_fp, "" __VA_ARGS__)
369     #define traceEntry(...) tracefEntry(Params.trace_fp, "" __VA_ARGS__)
370     #define traceExit(...)  tracefExit(Params.trace_fp, "" __VA_ARGS__)
371     #define closeTrace()    trace_close(Params.trace_fp)
372 #else
373     #define trace(...)
374     #define traceEntry(...)
375     #define traceExit(...)
376     #define closeTrace()
377 #endif
378 
379 //------------------------------ Miscellaneous -------------------------------//
380 
381 void *Malloc(size_t sz);
382 
383 bool promptable();
384 
385 bool interactive();
386 
387 size_t slprintf(char *buf, char *lim, char const *format, ...);
388 
389 rc_t strtooff(char const *str, char const **endptr, hoff_t *result, int infi);
390 
391 rc_t strtosz(char const *str, hoff_t *result);
392 
393 void endianize(uint8_t *buf, hoff_t len);
394 
395 #define maxOctetWidth(l) ( ((l) / DISP_CHCNT) + (((l) % DISP_CHCNT) ? 1 : 0) )
396 
397 rc_t textToOctetArray(char const *str, int mode, hoff_t *b_sz,
398                       uint8_t *buf, uint8_t *masks);
399 
400 char *cleanstring(char const *original_path);
401 
402 void outputProgress(hoff_t complete, hoff_t total, int isbackup);
403 
404 #ifdef HEXPEEK_EDITABLE_CONSOLE
405     #define progress(c, t, i) outputProgress(c, t, i)
406 #else
407     #define progress(c, t, i)
408 #endif
409 
410 //------------------------------ Error Handling ------------------------------//
411 
412 void terminate(int result);
413 
414 void doErr(char const *file, int line, int op, char const *fmt, ...);
415 
416 #define PGPRE PRGNM ": "
417 
418 #define prerr(...) doErr(SRCNAME, __LINE__, 0, PGPRE __VA_ARGS__)
419 #define malcmd(...) doErr(SRCNAME, __LINE__, 0, PGPRE "malformed command: " __VA_ARGS__)
420 #define malnum(...) doErr(SRCNAME, __LINE__, 0, PGPRE "malformed number: " __VA_ARGS__)
421 
422 #define prwarn(...) doErr(SRCNAME, __LINE__, 1, PGPRE "warning: " __VA_ARGS__)
423 
424 void doDie(char const *file, int line);
425 
426 #define die() doDie(SRCNAME, __LINE__)
427 
428 bool doCheck(char const *file, int line, char const *msg, bool exp);
429 
430 #define assert(e) doCheck(SRCNAME, __LINE__, (#e), (e))
431 
432 //------------------------------- Console I/O --------------------------------//
433 
434 void consoleInit();
435 
436 void consoleClose();
437 
438 char *consoleIn();
439 
440 void console(char const *format, ...);
441 
442 void hexpeek_genf(char *out, char const *in);
443 
444 void consoleOutf(char const *format, ...);
445 
446 void consoleFlush();
447 
448 int consoleAsk(char const *format, ...);
449 
450 //--------------------------------- File I/O ---------------------------------//
451 
452 char const *fdname(int fd);
453 
454 rc_t hexpeek_open(char const *path, int flags, mode_t mode, int *fd);
455 
456 hoff_t hexpeek_seek(int descriptor, hoff_t offset, int whence);
457 
458 #define SAVE_OFFSET(d, o) \
459     assert(((o) = hexpeek_seek((d), 0, SEEK_CUR)) != -1);
460 
461 #define RESTORE_OFFSET(d, o) \
462     assert(hexpeek_seek((d), (o), SEEK_SET) == (o));
463 
464 rc_t seekto(int descriptor, hoff_t offset);
465 
466 ssize_t readfull(int descriptor, void *buf, size_t count);
467 
468 hoff_t hexpeek_read(int descriptor, void *buf, hoff_t count);
469 
470 hoff_t hexpeek_write(int descriptor, const void *buf, hoff_t count);
471 
472 rc_t hexpeek_stat(int descriptor, struct stat *fileinfo);
473 
474 rc_t hexpeek_sync(int descriptor);
475 
476 rc_t hexpeek_syncdir(char const *path);
477 
478 rc_t hexpeek_truncate(int descriptor, hoff_t len);
479 
480 int sameness(int fd0, int fd1);
481 
482 bool isseekable(int file_index);
483 
484 hoff_t filesize(int file_index);
485 
486 hoff_t pathsize(char const *path);
487 
488 rc_t readat(int descriptor, hoff_t at, void *buf, hoff_t count);
489 
490 rc_t writeat(int descriptor, hoff_t at, const void *buf, hoff_t count);
491 
492 rc_t filecpy(int src_fd, hoff_t src_at, hoff_t src_len,
493              int dst_fd, hoff_t dst_at, hoff_t dst_len);
494 
495 rc_t lclcpy(int fd, hoff_t src_at, hoff_t dst_at, hoff_t length);
496 
497 rc_t adjustSize(int data_fi, hoff_t pos, hoff_t amt, int backup_fd);
498 
499 //------------------------------- Backup File --------------------------------//
500 
501 #define BACKUP_EXT PRGNM "-backup"
502 
503 #define MAX_BACKUP_DEPTH  0x20
504 #define DEFAULT_BACKUP_DEPTH 8
505 
506 int backupFd(int data_fi);
507 
508 rc_t makeBackup(ParsedCommand const *ppc);
509 
510 rc_t makeAdjBackup(int data_fi, int backup_fd, hoff_t sv_from);
511 
512 rc_t clearAdjBackup(int backup_fd, void *vp);
513 
514 rc_t recoverBackup(int data_fi, int what);
515 
516 //--------------------------- Settings Processing ----------------------------//
517 
518 hoff_t outputWidth(int part, int formode, hoff_t linewh);
519 
520 int ascertainShared(char const *str, int *subtype, char const **post);
521 
522 rc_t processShared(int cmd, int subtype, char const *arg, int formode);
523 
524 rc_t parseArgv(int argc, char **argv);
525 
526 //------------------------------- Test Plugins -------------------------------//
527 
528 #ifdef HEXPEEK_PLUGINS
529     rc_t plugin_argv(int argc, char **argv, int *which);
530     void* plugin(int type, void *vp);
531 #else
532     #define plugin_argv(a, v, w) RC_NIL
533     #define plugin(t, v)
534 #endif
535 
536 #endif
537