32-bit fixes for encoding of search criteria

This commit is contained in:
Patrick Simpson 2017-02-28 14:02:52 +01:00
parent 0cda2fa0c1
commit 7a885acb71
3 changed files with 91 additions and 68 deletions

View File

@ -66,8 +66,7 @@ namespace Acacia.Native.MAPI
} }
} }
// TODO: align is probably wrong for 32-bit [StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
public struct PropValue public struct PropValue
{ {
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
@ -124,7 +123,9 @@ namespace Acacia.Native.MAPI
// LONG x; /* case PT_NULL, PT_OBJECT (no usable value) */ // LONG x; /* case PT_NULL, PT_OBJECT (no usable value) */
} }
[FieldOffset(0)]
public Header header; public Header header;
[FieldOffset(8)]
public Data data; public Data data;
public override string ToString() public override string ToString()
@ -160,13 +161,13 @@ namespace Acacia.Native.MAPI
return encoder.Allocate(obj.header, obj.data.b); return encoder.Allocate(obj.header, obj.data.b);
case PropType.STRING8: case PropType.STRING8:
IntPtr ptrA = encoder.Allocate(Encoding.ASCII.GetBytes((string)value), new byte[] { 0 }); IntPtr ptrA = encoder.Allocate(Encoding.ASCII.GetBytes((string)value), new byte[] { 0 });
return encoder.Allocate(obj.header, ptrA); return encoder.Allocate(obj.header, 8, ptrA);
case PropType.UNICODE: case PropType.UNICODE:
IntPtr ptrW = encoder.Allocate(Encoding.Unicode.GetBytes((string)value), new byte[] { 0, 0 }); IntPtr ptrW = encoder.Allocate(Encoding.Unicode.GetBytes((string)value), new byte[] { 0, 0 });
return encoder.Allocate(obj.header, ptrW); return encoder.Allocate(obj.header, 8, ptrW);
case PropType.BINARY: case PropType.BINARY:
obj.data.bin = ((SBinary)value).Marshal(encoder); obj.data.bin = ((SBinary)value).Marshal(encoder);
return encoder.Allocate(obj.header, obj.data.bin); return encoder.Allocate(obj.header, 8, obj.data.bin);
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -207,53 +207,62 @@ namespace Acacia.Native.MAPI
} }
} }
// TODO: check this on 32 bit machines [StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Explicit)]
unsafe public struct SRestriction unsafe public struct SRestriction
{ {
[FieldOffset(0)] [StructLayout(LayoutKind.Sequential)]
public RestrictionType rt; public struct Header
{
public RestrictionType rt;
}
// And/Or [StructLayout(LayoutKind.Explicit)]
[FieldOffset(8)] unsafe public struct Data
public SubRestriction sub; {
// And/Or
[FieldOffset(0)]
public SubRestriction sub;
[FieldOffset(8)] [FieldOffset(0)]
public NotRestriction not; public NotRestriction not;
[FieldOffset(8)] [FieldOffset(0)]
public ContentRestriction content; public ContentRestriction content;
[FieldOffset(8)] [FieldOffset(0)]
public PropertyRestriction prop; public PropertyRestriction prop;
[FieldOffset(8)] [FieldOffset(0)]
public BitMaskRestriction bitMask; public BitMaskRestriction bitMask;
[FieldOffset(8)] [FieldOffset(0)]
public ExistRestriction exist; public ExistRestriction exist;
[FieldOffset(8)] [FieldOffset(0)]
public CommentRestriction comment; public CommentRestriction comment;
}
public Header header;
public Data data;
public SearchQuery ToSearchQuery() public SearchQuery ToSearchQuery()
{ {
switch (rt) switch (header.rt)
{ {
case RestrictionType.AND: case RestrictionType.AND:
return sub.ToSearchQuery(true); return data.sub.ToSearchQuery(true);
case RestrictionType.OR: case RestrictionType.OR:
return sub.ToSearchQuery(false); return data.sub.ToSearchQuery(false);
case RestrictionType.NOT: case RestrictionType.NOT:
return not.ToSearchQuery(); return data.not.ToSearchQuery();
case RestrictionType.CONTENT: case RestrictionType.CONTENT:
return content.ToSearchQuery(); return data.content.ToSearchQuery();
case RestrictionType.PROPERTY: case RestrictionType.PROPERTY:
return prop.ToSearchQuery(); return data.prop.ToSearchQuery();
case RestrictionType.BITMASK: case RestrictionType.BITMASK:
return bitMask.ToSearchQuery(); return data.bitMask.ToSearchQuery();
case RestrictionType.EXIST: case RestrictionType.EXIST:
return exist.ToSearchQuery(); return data.exist.ToSearchQuery();
/* TODO COMPAREPROPS, /* TODO COMPAREPROPS,
BITMASK, BITMASK,
@ -275,27 +284,27 @@ namespace Acacia.Native.MAPI
public string ToString(int depth) public string ToString(int depth)
{ {
string indent = new string(' ', depth); string indent = new string(' ', depth);
string s = indent + rt.ToString() + "\n" + indent + "{\n"; string s = indent + header.rt.ToString() + "\n" + indent + "{\n";
switch (rt) switch (header.rt)
{ {
case RestrictionType.AND: case RestrictionType.AND:
case RestrictionType.OR: case RestrictionType.OR:
s += sub.ToString(depth + 1); s += data.sub.ToString(depth + 1);
break; break;
case RestrictionType.NOT: case RestrictionType.NOT:
s += not.ToString(depth + 1); s += data.not.ToString(depth + 1);
break; break;
case RestrictionType.CONTENT: case RestrictionType.CONTENT:
s += content.ToString(depth + 1); s += data.content.ToString(depth + 1);
break; break;
case RestrictionType.PROPERTY: case RestrictionType.PROPERTY:
s += prop.ToString(depth + 1); s += data.prop.ToString(depth + 1);
break; break;
case RestrictionType.BITMASK: case RestrictionType.BITMASK:
s += bitMask.ToString(depth + 1); s += data.bitMask.ToString(depth + 1);
break; break;
case RestrictionType.EXIST: case RestrictionType.EXIST:
s += exist.ToString(depth + 1); s += data.exist.ToString(depth + 1);
break; break;
/* TODO COMPAREPROPS, /* TODO COMPAREPROPS,
@ -361,15 +370,15 @@ namespace Acacia.Native.MAPI
public void Encode(SearchQuery.PropertyExists part) public void Encode(SearchQuery.PropertyExists part)
{ {
Current->rt = RestrictionType.EXIST; Current->header.rt = RestrictionType.EXIST;
Current->exist.prop = part.Property.Tag; Current->data.exist.prop = part.Property.Tag;
} }
public void Encode(SearchQuery.Or part) public void Encode(SearchQuery.Or part)
{ {
Current->rt = RestrictionType.OR; Current->header.rt = RestrictionType.OR;
Current->sub.cb = (uint)part.Operands.Count; Current->data.sub.cb = (uint)part.Operands.Count;
Current->sub.ptr = EncodePointer(part.Operands); Current->data.sub.ptr = EncodePointer(part.Operands);
} }
public void Encode(SearchQuery.PropertyIdentifier part) public void Encode(SearchQuery.PropertyIdentifier part)
@ -380,15 +389,15 @@ namespace Acacia.Native.MAPI
public void Encode(SearchQuery.Not part) public void Encode(SearchQuery.Not part)
{ {
Current->rt = RestrictionType.NOT; Current->header.rt = RestrictionType.NOT;
Current->not.ptr = EncodePointer(new[] { part.Operand }); Current->data.not.ptr = EncodePointer(new[] { part.Operand });
} }
public void Encode(SearchQuery.And part) public void Encode(SearchQuery.And part)
{ {
Current->rt = RestrictionType.AND; Current->header.rt = RestrictionType.AND;
Current->sub.cb = (uint)part.Operands.Count; Current->data.sub.cb = (uint)part.Operands.Count;
Current->sub.ptr = EncodePointer(part.Operands); Current->data.sub.ptr = EncodePointer(part.Operands);
} }
private SRestriction* EncodePointer(IEnumerable<SearchQuery> operands) private SRestriction* EncodePointer(IEnumerable<SearchQuery> operands)
@ -425,26 +434,26 @@ namespace Acacia.Native.MAPI
public void Encode(SearchQuery.PropertyContent part) public void Encode(SearchQuery.PropertyContent part)
{ {
Current->rt = RestrictionType.CONTENT; Current->header.rt = RestrictionType.CONTENT;
Current->content.ulFuzzyLevel = ContentRestriction.FuzzyLevelFromSearchQuery(part); Current->data.content.ulFuzzyLevel = ContentRestriction.FuzzyLevelFromSearchQuery(part);
Current->content.ulPropTag = part.Property.Tag; Current->data.content.ulPropTag = part.Property.Tag;
Current->content.prop = (PropValue*)PropValue.MarshalFromObject(this, part.Property.Tag, part.Content); Current->data.content.prop = (PropValue*)PropValue.MarshalFromObject(this, part.Property.Tag, part.Content);
} }
public void Encode(SearchQuery.PropertyCompare part) public void Encode(SearchQuery.PropertyCompare part)
{ {
Current->rt = RestrictionType.PROPERTY; Current->header.rt = RestrictionType.PROPERTY;
Current->prop.relop = (SearchOperation)part.Operation; Current->data.prop.relop = (SearchOperation)part.Operation;
Current->prop.ulPropTag = part.Property.Tag; Current->data.prop.ulPropTag = part.Property.Tag;
Current->prop.prop = (PropValue*)PropValue.MarshalFromObject(this, part.Property.Tag, part.Value); Current->data.prop.prop = (PropValue*)PropValue.MarshalFromObject(this, part.Property.Tag, part.Value);
} }
public void Encode(SearchQuery.PropertyBitMask part) public void Encode(SearchQuery.PropertyBitMask part)
{ {
Current->rt = RestrictionType.BITMASK; Current->header.rt = RestrictionType.BITMASK;
Current->bitMask.bmr = (BMR)(int)part.Operation; Current->data.bitMask.bmr = (BMR)(int)part.Operation;
Current->bitMask.prop = part.Property.Tag; Current->data.bitMask.prop = part.Property.Tag;
Current->bitMask.mask = part.Mask; Current->data.bitMask.mask = part.Mask;
} }
} }

View File

@ -134,27 +134,40 @@ namespace Acacia.Native
int size = 0; int size = 0;
int[] starts = new int[all.Length]; int[] starts = new int[all.Length];
object[] encode = new object[all.Length];
int used = 0;
int align = -1;
for (int i = 0; i < all.Length; ++i) for (int i = 0; i < all.Length; ++i)
{ {
starts[i] = Align(size); if (all[i] is int)
{
align = (int)all[i];
++i;
}
starts[used] = Align(size, align);
int thisSize = Marshal.SizeOf(all[i]); int thisSize = Marshal.SizeOf(all[i]);
size = starts[i] + thisSize; size = starts[used] + thisSize;
encode[used] = all[i];
align = -1;
++used;
} }
AllocationBase alloc = Allocate(size); AllocationBase alloc = Allocate(size);
IntPtr ptr = alloc.Pointer; IntPtr ptr = alloc.Pointer;
for (int i = 0; i < all.Length; ++i) for (int i = 0; i < used; ++i)
{ {
Marshal.StructureToPtr(all[i], ptr + starts[i], false); Marshal.StructureToPtr(encode[i], ptr + starts[i], false);
} }
return alloc.Pointer; return alloc.Pointer;
} }
private int Align(int size) private int Align(int size, int align)
{ {
int align = Marshal.SizeOf<IntPtr>(); if (align < 0)
align = Marshal.SizeOf<IntPtr>();
int additional = (align - (size % align)) % align; int additional = (align - (size % align)) % align;
return size + additional; return size + additional;
} }