[aravis] zip: fix issue on platform not supporting unaligned memory access.



commit cb6dd5193295dd439f76041733df555f4c940501
Author: Nial Peters <nonbiostudent hotmail com>
Date:   Sun Jul 15 18:00:14 2012 +0200

    zip: fix issue on platform not supporting unaligned memory access.

 docs/reference/aravis/aravis-sections.txt |    4 ++
 src/arvzip.c                              |   35 +++++++--------
 src/arvzip.h                              |   68 +++++++++++++++++++++++++++++
 tests/.gitignore                          |    1 +
 tests/Makefile.am                         |    5 ++-
 tests/misc.c                              |   56 +++++++++++++++++++++++
 6 files changed, 149 insertions(+), 20 deletions(-)
---
diff --git a/docs/reference/aravis/aravis-sections.txt b/docs/reference/aravis/aravis-sections.txt
index caeeb3b..54e67ec 100644
--- a/docs/reference/aravis/aravis-sections.txt
+++ b/docs/reference/aravis/aravis-sections.txt
@@ -1443,6 +1443,10 @@ arv_zip_get_file
 arv_zip_get_file_list
 arv_zip_file_get_name
 arv_zip_file_get_uncompressed_size
+ARV_GUINT16_FROM_LE_PTR
+ARV_GUINT32_FROM_LE_PTR
+arv_guint16_from_unaligned_le_ptr
+arv_guint32_from_unaligned_le_ptr
 <SUBSECTION Private>
 ArvZipFile
 </SECTION>
diff --git a/src/arvzip.c b/src/arvzip.c
index 39e7267..891b1a0 100644
--- a/src/arvzip.c
+++ b/src/arvzip.c
@@ -35,9 +35,6 @@
 #include <string.h>
 #include <zlib.h>
 
-#define GUINT32_FROM_LE_PTR(ptr) GUINT32_FROM_LE(*((guint32 *)(ptr)))
-#define GUINT16_FROM_LE_PTR(ptr) GUINT16_FROM_LE(*((guint16 *)(ptr)))
-
 struct _ArvZipFile {
         char *name;
 
@@ -87,27 +84,27 @@ arv_zip_build_file_list (ArvZip *zip)
 
 	for (i = 0; i < zip->n_files; i++) {
 		ptr = zip->buffer + zip->header_size + offset;
-		if (GUINT32_FROM_LE_PTR (ptr) != 0x02014b50) {
+		if (ARV_GUINT32_FROM_LE_PTR (ptr) != 0x02014b50) {
 			arv_debug_misc ("[Zip::build_file_list] Magic number of central directory not found (0x02014b50)");
 			arv_debug_misc ("[Zip::build_file_list] Expected at 0x%08x - found 0x%08x instead",
-					zip->header_size + offset, GUINT32_FROM_LE_PTR (ptr));
+					zip->header_size + offset, ARV_GUINT32_FROM_LE_PTR (ptr));
 		       	return;
 		}
 
 		zip_file = g_new0 (ArvZipFile, 1);
-                zip_file->compressed_size = GUINT32_FROM_LE_PTR (ptr + 20);
-                zip_file->uncompressed_size = GUINT32_FROM_LE_PTR (ptr + 24);
-                zip_file->offset = GUINT32_FROM_LE_PTR (ptr + 42);
-		zip_file->name = g_strndup ((char *) (ptr + 46), GUINT16_FROM_LE_PTR (ptr + 28));
+                zip_file->compressed_size = ARV_GUINT32_FROM_LE_PTR (ptr + 20);
+                zip_file->uncompressed_size = ARV_GUINT32_FROM_LE_PTR (ptr + 24);
+                zip_file->offset = ARV_GUINT32_FROM_LE_PTR (ptr + 42);
+		zip_file->name = g_strndup ((char *) (ptr + 46), ARV_GUINT16_FROM_LE_PTR (ptr + 28));
 
 		arv_log_misc ("[Zip::list_files] %s", zip_file->name);
 
 		zip->files = g_slist_prepend (zip->files, zip_file);
 
                 offset += 0x2e +
-			GUINT16_FROM_LE_PTR (ptr + 28) + /* filename size */
-			GUINT16_FROM_LE_PTR (ptr + 30) + /* extra field */
-			GUINT16_FROM_LE_PTR (ptr + 32);  /* file comment */
+			ARV_GUINT16_FROM_LE_PTR (ptr + 28) + /* filename size */
+			ARV_GUINT16_FROM_LE_PTR (ptr + 30) + /* extra field */
+			ARV_GUINT16_FROM_LE_PTR (ptr + 32);  /* file comment */
 	}
 }
 
@@ -133,14 +130,14 @@ arv_zip_get_file_data (ArvZip *zip, ArvZipFile *zip_file)
 
 	ptr = zip->buffer + zip_file->offset + zip->header_size;
 
-        if (GUINT32_FROM_LE_PTR (ptr) != 0x04034b50) {
+        if (ARV_GUINT32_FROM_LE_PTR (ptr) != 0x04034b50) {
 		arv_debug_misc ("[Zip::get_file_data] Magic number for file header not found (0x04034b50)");
 	       	return -1;
 	}
 
 	return zip_file->offset + zip->header_size +
-		GUINT16_FROM_LE_PTR (ptr + 26) +
-		GUINT16_FROM_LE_PTR (ptr + 28) + 30;
+		ARV_GUINT16_FROM_LE_PTR (ptr + 26) +
+		ARV_GUINT16_FROM_LE_PTR (ptr + 28) + 30;
 }
 
 /**
@@ -182,15 +179,15 @@ arv_zip_new (const void *buffer, size_t size)
 	}
 
 	ptr = zip->buffer + zip->directory_position;
-        zip->n_files = GUINT16_FROM_LE_PTR (ptr + 10);
-        if (GUINT16_FROM_LE_PTR (ptr + 8) != zip->n_files) {
+        zip->n_files = ARV_GUINT16_FROM_LE_PTR (ptr + 10);
+        if (ARV_GUINT16_FROM_LE_PTR (ptr + 8) != zip->n_files) {
 		arv_debug_misc ("[Zip::new] Mismatch in number of files");
 		zip->n_files = 0;
 		return zip;
         }
 
-        zip->directory_size = GUINT32_FROM_LE_PTR (ptr + 12);
-        zip->directory_offset = GUINT32_FROM_LE_PTR (ptr + 16);
+        zip->directory_size = ARV_GUINT32_FROM_LE_PTR (ptr + 12);
+        zip->directory_offset = ARV_GUINT32_FROM_LE_PTR (ptr + 16);
         zip->header_size = zip->directory_position - (zip->directory_offset + zip->directory_size);
 
 	arv_log_misc ("[Zip::new] number of files = %d", zip->n_files);
diff --git a/src/arvzip.h b/src/arvzip.h
index 2ea5c4d..bcb9e07 100644
--- a/src/arvzip.h
+++ b/src/arvzip.h
@@ -35,6 +35,74 @@ const GSList *	arv_zip_get_file_list	(ArvZip *zip);
 const char *	arv_zip_file_get_name			(ArvZipFile *zip_file);
 size_t		arv_zip_file_get_uncompressed_size	(ArvZipFile *zip_file);
 
+#define ARV_GUINT32_FROM_LE_PTR(ptr) arv_guint32_from_unaligned_le_ptr (ptr)
+#define ARV_GUINT16_FROM_LE_PTR(ptr) arv_guint16_from_unaligned_le_ptr (ptr)
+
+/**
+ * arv_guint32_from_unaligned_le_ptr:
+ * @ptr: pointer to a little endian 32 bit usigned integer
+ *
+ * Here's an excerpt of the ARM documentation:
+ *
+ * "Unaligned data access in C and C++ code
+ *
+ * It can be necessary to access unaligned data in memory, for example,
+ * when porting legacy code from a CISC architecture where instructions are
+ * available to directly access unaligned data in memory.
+ * 
+ * On ARMv4 and ARMv5 architectures, and on the ARMv6 architecture
+ * depending on how it is configured, care is required when accessing
+ * unaligned data in memory, to avoid unexpected results. For example, when
+ * a conventional pointer is used to read a word in C or C++ source code,
+ * the ARM compiler generates assembly language code that reads the word
+ * using an LDR instruction. This works as expected when the address is a
+ * multiple of four, for example if it lies on a word boundary. However, if
+ * the address is not a multiple of four, the LDR instruction returns a
+ * rotated result rather than performing a true unaligned word load.
+ * Generally, this rotation is not what the programmer expects.
+ * 
+ * On ARMv6 and later architectures, unaligned access is fully supported."
+ *
+ * Returns: a guint32 in machine endianess
+ */
+
+static inline guint32
+arv_guint32_from_unaligned_le_ptr (const void *ptr)
+{
+	guint32 val;
+
+	g_return_val_if_fail (ptr != NULL, 0);
+
+	*((char*)(&val)) = *((char*)ptr);
+	*(((char*)(&val))+1) = *(((char*)ptr)+1);
+	*(((char*)(&val))+2) = *(((char*)ptr)+2);
+	*(((char*)(&val))+3) = *(((char*)ptr)+3);
+
+	return GUINT32_FROM_LE (val);
+}
+
+/**
+ * arv_guint16_from_unaligned_le_ptr:
+ * @ptr: pointer to a little endian 16 bit usigned integer
+ *
+ * See @arv_guint32_from_unaligned_le_ptr.
+ *
+ * Returns: a guint16 in machine endianess
+ */
+
+static inline guint16
+arv_guint16_from_unaligned_le_ptr (const void *ptr)
+{
+	guint16 val;
+
+	g_return_val_if_fail (ptr != NULL, 0);
+
+	*((char*)(&val)) = *((char*)ptr);
+	*(((char*)(&val))+1) = *(((char*)ptr)+1);
+
+	return GUINT16_FROM_LE (val);
+}
+
 G_END_DECLS
 
 #endif
diff --git a/tests/.gitignore b/tests/.gitignore
index 120d415..21574dd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,6 +1,7 @@
 evaluator
 genicam
 buffer
+misc
 fake
 cpp
 arv-test
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ca721cb..5d58ee2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -26,7 +26,7 @@ arv_camera_test_LDADD = $(test_progs_ldadd)
 arv_heartbeat_test_SOURCES = arvheartbeattest.c
 arv_heartbeat_test_LDADD = $(test_progs_ldadd)
 
-TEST_PROGS += evaluator buffer fake genicam
+TEST_PROGS += evaluator buffer misc fake genicam
 if ARAVIS_BUILD_CPP_TEST
 TEST_PROGS += cpp
 endif
@@ -39,6 +39,9 @@ evaluator_LDADD = $(test_progs_ldadd)
 buffer_SOURCES = buffer.c
 buffer_LDADD = $(test_progs_ldadd)
 
+misc_SOURCES = misc.c
+misc_LDADD = $(test_progs_ldadd)
+
 fake_SOURCES = fake.c
 fake_CFLAGS = -DGENICAM_FILENAME="\"$(top_srcdir)/src/arv-fake-camera.xml\""
 fake_LDADD = $(test_progs_ldadd)
diff --git a/tests/misc.c b/tests/misc.c
new file mode 100644
index 0000000..6ec846d
--- /dev/null
+++ b/tests/misc.c
@@ -0,0 +1,56 @@
+#include <glib.h>
+#include <arv.h>
+#include <string.h>
+
+static void
+unaligned_from_le_ptr_test (void)
+{
+	char test[]= {'\x11', '\x22', '\x33', '\x44','\x55', '\x66', '\x77', '\x88', '\x99', '\xaa', '\xbb', '\xcc'};
+	guint32 v_uint32;
+	guint16 v_uint16;
+
+	v_uint32 = ARV_GUINT32_FROM_LE_PTR (&test[0]);
+	g_assert_cmpuint (v_uint32, ==, 0x44332211);
+
+	v_uint32 = ARV_GUINT32_FROM_LE_PTR (&test[1]);
+	g_assert_cmpuint (v_uint32, ==, 0x55443322);
+	
+	v_uint32 = ARV_GUINT32_FROM_LE_PTR (&test[2]);
+	g_assert_cmpuint (v_uint32, ==, 0x66554433);
+	
+	v_uint32 = ARV_GUINT32_FROM_LE_PTR (&test[3]);
+	g_assert_cmpuint (v_uint32, ==, 0x77665544);
+
+	v_uint16 = ARV_GUINT16_FROM_LE_PTR (&test[0]);
+	g_assert_cmpuint (v_uint16, ==, 0x2211);
+	
+	v_uint16 = ARV_GUINT16_FROM_LE_PTR (&test[1]);
+	g_assert_cmpuint (v_uint16, ==, 0x3322);
+	
+	v_uint16 = ARV_GUINT16_FROM_LE_PTR (&test[2]);
+	g_assert_cmpuint (v_uint16, ==, 0x4433);
+	
+	v_uint16 = ARV_GUINT16_FROM_LE_PTR (&test[3]);
+	g_assert_cmpuint (v_uint16, ==, 0x5544);
+}
+
+int
+main (int argc, char *argv[])
+{
+	int result;
+	int i;
+
+	g_test_init (&argc, &argv, NULL);
+
+	g_type_init ();
+
+	g_test_add_func ("/buffer/unaligned-from-le", unaligned_from_le_ptr_test);
+
+	result = g_test_run();
+
+	arv_shutdown ();
+
+	return result;
+}
+
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]