[PATCH] Add conv=swab support to dd

Álvaro Fernández Rojas noltari at gmail.com
Sat Jul 27 17:22:28 UTC 2013


This patch adds support for swapping the endiannes of a file.
It's based on GNU coreutils "dd.c".

Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
---
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 96602eb..038fc4a 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -10,7 +10,7 @@
 
 //usage:#define dd_trivial_usage
 //usage:       "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n"
-//usage:       "	[seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]")
+//usage:       "	[seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync|swab]")
 //usage:#define dd_full_usage "\n\n"
 //usage:       "Copy a file with converting and formatting\n"
 //usage:     "\n	if=FILE		Read from FILE instead of stdin"
@@ -30,6 +30,7 @@
 //usage:     "\n	conv=noerror	Continue after read errors"
 //usage:     "\n	conv=sync	Pad blocks with zeros"
 //usage:     "\n	conv=fsync	Physically write data out before finishing"
+//usage:     "\n	conv=swab	Swap the order of every pair of input bytes"
 //usage:	)
 //usage:     "\n"
 //usage:     "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),"
@@ -42,6 +43,8 @@
 
 #include "libbb.h"
 
+#define SWAB_ALIGN_OFFSET 2
+
 /* This is a NOEXEC applet. Be very careful! */
 
 
@@ -139,6 +142,42 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
 	return 0;
 }
 
+/* If true, the last char from the previous call to 'swab_buffer'
+	is saved in 'saved_char'. */
+static bool char_is_saved = false;
+/* Odd char from previous call. */
+static char saved_char;
+/* Swap NREAD bytes in BUF, plus possibly an initial char from the
+	previous call. If NREAD is odd, save the last char for the
+	next call. Return the new start of the BUF buffer. */
+static char *swab_buffer(char *buf, size_t *nread)
+{
+	char *bufstart = buf, *cp;
+	size_t i;
+
+	/* Is a char left from last time? */
+	if (char_is_saved) {
+		*--bufstart = saved_char;
+		(*nread)++;
+		char_is_saved = false;
+    }
+
+	if (*nread & 1) {
+		/* An odd number of chars are in the buffer. */
+		saved_char = bufstart[--*nread];
+		char_is_saved = true;
+	}
+
+	/* Do the byte-swapping by moving every second character two
+		positions toward the end, working from the end of the buffer
+		toward the beginning. This way we only move half of the data. */
+	cp = bufstart + *nread;	/* Start one char past the last. */
+	for (i = *nread / 2; i; i--, cp -= 2)
+		*cp = *(cp - 2);
+
+	return ++bufstart;
+}
+
 #if ENABLE_LFS
 # define XATOU_SFX xatoull_sfx
 #else
@@ -155,9 +194,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 		FLAG_SYNC    = 1 << 1,
 		FLAG_NOERROR = 1 << 2,
 		FLAG_FSYNC   = 1 << 3,
+		FLAG_SWAB    = 1 << 4,
 		/* end of conv flags */
-		FLAG_TWOBUFS = 1 << 4,
-		FLAG_COUNT   = 1 << 5,
+		FLAG_TWOBUFS = 1 << 5,
+		FLAG_COUNT   = 1 << 6,
 	};
 	static const char keywords[] ALIGN1 =
 		"bs\0""count\0""seek\0""skip\0""if\0""of\0"
@@ -167,7 +207,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 		;
 #if ENABLE_FEATURE_DD_IBS_OBS
 	static const char conv_words[] ALIGN1 =
-		"notrunc\0""sync\0""noerror\0""fsync\0";
+		"notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
 #endif
 	enum {
 		OP_bs = 0,
@@ -185,11 +225,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 		OP_conv_sync,
 		OP_conv_noerror,
 		OP_conv_fsync,
+		OP_conv_swab,
 	/* Unimplemented conv=XXX: */
 	//nocreat       do not create the output file
 	//excl          fail if the output file already exists
 	//fdatasync     physically write output file data before finishing
-	//swab          swap every pair of input bytes
 	//lcase         change upper case to lower case
 	//ucase         change lower case to upper case
 	//block         pad newline-terminated records with spaces to cbs-size
@@ -303,7 +343,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 	} /* end of "for (argv[n])" */
 
 //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
-	ibuf = obuf = xmalloc(ibs);
+	ibuf = obuf = xmalloc(ibs + SWAB_ALIGN_OFFSET * 2);
+	ibuf += SWAB_ALIGN_OFFSET;	/* allow space for swab */
 	if (ibs != obs) {
 		flags |= FLAG_TWOBUFS;
 		obuf = xmalloc(obs);
@@ -384,6 +425,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 				n = ibs;
 			}
 		}
+
+		if (flags & FLAG_SWAB) {
+			ibuf = swab_buffer(ibuf, &n);
+		}
+
 		if (flags & FLAG_TWOBUFS) {
 			char *tmp = ibuf;
 			while (n) {


More information about the busybox mailing list