-Fixed Issue 27
-Enhanced the processing of files with uncommon combinations of FileAligment and PointerToRawData values

git-svn-id: http://pefile.googlecode.com/svn/trunk@107 8842bc4e-7134-0410-8230-5dc5194fb5c1
diff --git a/pefile.py b/pefile.py
index c5632fc..10fdab1 100644
--- a/pefile.py
+++ b/pefile.py
@@ -573,6 +573,9 @@
             obj.__dict__[flag[0]] = False
 
 
+def power_of_two(val):
+    return val != 0 and (val & (val-1)) == 0
+
 # According to http://corkami.blogspot.com/2010/01/parce-que-la-planche-aura-brule.html
 # if PointerToRawData is less that 0x200 it's rounded to zero. Loading the test file
 # in a debugger it's easy to verify that the PointerToRawData value of 1 is rounded
@@ -585,11 +588,22 @@
 #  The default is 512. If the SectionAlignment is less than the architecture’s page
 #  size, then FileAlignment must match SectionAlignment."
 #
-def adjust_FileAlignment( val, file_aligment ):
+# The following is a hardcoded constant if the Windows loader
+FILE_ALIGNEMNT_HARDCODED_VALUE = 0x200
+FileAlignment_Warning = False # We only want to print the warning once
+def adjust_FileAlignment( val, file_alignment ):
+    
+    if file_alignment > FILE_ALIGNEMNT_HARDCODED_VALUE:
+        # If it's not a power of two, report it:
+        if not power_of_two(file_alignment) and FileAlignment_Warning is False:
+            self.__warnings.append(
+                'If FileAlignment > 0x200 it should be a power of 2. Value: %x' % (
+                    file_alignment)  )
+            FileAlignment_Warning = True
 
-    #if file_aligment and val % file_aligment:
-    #    return file_aligment * ( val / file_aligment )
-    return val
+    if file_alignment < FILE_ALIGNEMNT_HARDCODED_VALUE:
+        return val
+    return (val / 0x200) * 0x200
 
 
 # According to the document: 
@@ -598,10 +612,18 @@
 #  greater than or equal to FileAlignment. The default is the page size for the
 #  architecture."
 #
-def adjust_SectionAlignment( val, section_alignment, file_aligment ):
+SectionAlignment_Warning = False # We only want to print the warning once
+def adjust_SectionAlignment( val, section_alignment, file_alignment ):
 
+    if file_alignment < FILE_ALIGNEMNT_HARDCODED_VALUE:
+        if file_alignment != section_alignment and SectionAlignment_Warning is False:
+            self.__warnings.append(
+                'If FileAlignment(%x) < 0x200 it should equal SectionAlignment(%x)' % (
+                    file_alignment, section_alignment)  )
+            SectionAlignment_Warning = True
+        
     if section_alignment < 0x1000: # page size
-        section_alignment = file_aligment
+        section_alignment = file_alignment
         
     # 0x200 is the minimum valid FileAlignment according to the documentation
     # although ntoskrnl.exe has an alignment of 0x80 in some Windows versions
@@ -2240,9 +2262,8 @@
                 ( section.PointerToRawData % self.OPTIONAL_HEADER.FileAlignment) != 0):
                 self.__warnings.append(
                     ('Error parsing section %d. ' % i) +
-                    'Suspicious value for FileAlignment in the Optional Header. ' +
-                    'Normally the PointerToRawData entry of the sections\' structures ' +
-                    'is a multiple of FileAlignment, this might imply the file ' +
+                    'PointerToRawData should normally be ' +
+                    'a multiple of FileAlignment, this might imply the file ' +
                     'is trying to confuse tools which parse this incorrectly')
             
             
@@ -4391,9 +4412,12 @@
         offset is outside the file's boundaries.
         """
         
+        if not isinstance(data, str):
+            raise TypeError('data should be of type: str')
+
         offset = self.get_physical_by_rva(rva)
         if not offset:
-            raise False
+            return False
         
         return self.set_bytes_at_offset(offset, data)