Einzelnen Beitrag anzeigen

lagalex

Registriert seit: 16. Jan 2011
7 Beiträge
 
#6

AW: Datei mit dynamischen Array einlesen

  Alt 19. Feb 2013, 09:35
Hallo,
Vielen Dank für all die Hilfestellungen und Denkanregungen, hab zwar das Problem noch immer nicht durchschaut, bin aber so glaube ich zumindest mal einen Schritt weiter...

- Hab den Vorschlag mit ReadBuffer() umgesetzt
- Beim Ausführen bekomme ich einen RunError 203, also einen Heap Overflow

Anbei ist die shp-Datei als zip im Anhang, die ich versuche, einzulesen.
Es handelt sich hier um ein ESRI-Shapefile, die Dokumentation zum Aufbau der Datei ist hier : http://www.esri.com/library/whitepap.../shapefile.pdf

Ich habe die Datei mit einem HexEditor durchleutet und durchgezählt, von der Datei her passt auch alles wie laut Dokumentation, beinhaltet eine PolyLinie mit 1 Part und 6 Points

Werte ich allerdings mein Objekt ShapeFile aus zur Laufzeit, dann sehe ich, dass die Variablen NumParts und NumPoints irgendwelche unnachvollziehbare hohe Werte enthalten - deswegen wird anscheinend mein Array dann überverhältnismäßig groß dimensioniert und es kommt zu einem Heap Overflow.

Hier die Auswertung:
<TSHAPEFILE> = {
<TOBJECT> = {
_vptr$TOBJECT = $592b1c},
FILEHEADER = {
FILECODE = 9994,
UNUSED1 = 0,
UNUSED2 = 0,
UNUSED3 = 0,
UNUSED4 = 0,
UNUSED5 = 0,
FILELEN = 126,
VERSION = 1000,
SHAPETYPE = 3,
XMIN = 10,
YMIN = 10,
XMAX = 172.48123448885769,
YMAX = 115.67794078524194,
ZMIN = 0,
ZMAX = 0,
MMIN = 0,
MMAX = 0},
RECORDHEADER = {
NUMMER = 9280,
LAENGE = 0},
PLHEAD = {
SHAPETYPE = 1076101120,
BOX = {
75,
20,
27.288444271758017,
66.00672307939206},
NUMPARTS = 411976715,
NUMPOINTS = 1079176168},
PLCONTENT = {
PARTS = $0,
POINTS = $0},
ERROR = false,
ERRMSG = $0,
PUNKTE = $0,
POLYLINIEN = $2baed0}

------------------
und hier der Quelltext meiner Unit (hatte gestern den Code nur ungefähr abgeschrieben):

Delphi-Quellcode:
unit shapefiles;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

type TSHPFileHeader = packed record
     // Big Endian
     FileCode : LongInt;
     Unused1,
     Unused2,
     Unused3,
     Unused4,
     Unused5 : LongInt;
     FileLen : LongInt;
     // Little Endian
     Version : LongInt;
     ShapeType: LongInt;
     Xmin : Double;
     Ymin : Double;
     Xmax : Double;
     Ymax : Double;
     Zmin : Double;
     Zmax : Double;
     Mmin : Double;
     Mmax : Double;
     end;

type TRecordHeader = packed record
                Nummer : LongInt; // Big Endian
                Laenge : LongInt; // Big Endian
                end;

type TBox = Array[0..3] of Double;

type TPunkt = packed record
     ID : LongInt;
     X : Double;
     Y : Double;
     end;

type TPunktXY = record
           X, Y : Double;
           end;

type TPolyLine = record
            ShapeType : LongInt;
            Box : TBox;
            NumParts : LongInt;
            NumPoints : LongInt;
            Parts : Array Of LongInt;
            Points : Array Of TPunktXY;
            end;

type TPolyHeader = packed record
            Shapetype : LongInt;
            Box : TBox;
            NumParts : LongInt;
            NumPoints : LongInt;
            end;
type TPolyContent = packed record
            Parts : Array of LongInt;
            Points : Array of TPunktXY;
            end;

type TShapefile = class
      public
       FileHeader : TSHPFileHeader;
       RecordHeader : TRecordHeader;
       PLHead : TPolyHeader;
       PLContent : TPolyContent;
       error : boolean;
       errmsg : String;

       Punkte : Array Of TPunkt;
       PolyLinien : Array of TPolyLine;

       constructor Create;
       procedure AddPoint (ID : LongInt; X, Y : Double);
       procedure AddPLPart (ID : LongInt; zahl : LongInt);
       procedure LoadSHP(datnam : string);
     end;

const shpNullShape = 0;
      shpPoint = 1;
      shpPolyLine = 3;
      shpPolygon = 5;
      shpMultiPoint = 8;
      shpPointZ = 11;
      shpPolyLineZ = 13;
      shpPolygonZ = 15;
      shpMultiPointZ = 18;
      shpPointM = 21;
      shpPolyLineM = 23;
      shpPolygonM = 25;
      shpMultiPointM = 28;
      shpMultiPatch = 31;

      sizeHeader = 100;


procedure SwapBytes(Var Bytes; Len : Integer);


implementation

constructor TShapeFile.Create;
begin
 inherited;
 error:=false;
 // Dynamische Arrays auf 0 setzen
 SetLength(Punkte,0);
 SetLength(PolyLinien,0);
end;


procedure TShapeFile.AddPoint(ID : LongInt; X, Y : Double);
begin
 SetLength(Punkte,Length(Punkte)+1);
 Punkte[High(Punkte)].ID:=ID;
 Punkte[High(Punkte)].X:=X;
 Punkte[High(Punkte)].Y:=Y;
end;

procedure TShapeFile.AddPLPart (ID : LongInt; zahl : LongInt);
begin
 //if (High(PolyLinien)<ID) then SetLength(PolyLinien,ID+1);
 //
end;

procedure TShapefile.LoadSHP(datnam : string);
var Strom : TFileStream;
    In_Punkt : TPunkt;
    index : integer;
    i,j : integer;

begin
// Lies den Header des Shapefiles ein
try
  Strom:=TFileStream.Create(datnam,fmOpenRead);
  Strom.ReadBuffer(FileHeader,SizeOf(FileHeader));
except
  error:=true;
  errmsg:='Kein gültiges ESRI-Shapefile!';
  Strom.Free;
  exit;
end;
// Big Endian in Little Endian umwandeln
SwapBytes(FileHeader.FileCode,SizeOf(FileHeader.FileCode));
SwapBytes(FileHeader.FileLen,SizeOf(FileHeader.FileLen));
// Records einlesen
index:=0;
try
  repeat
    index:=index+1;
    Strom.ReadBuffer(RecordHeader, SizeOf(RecordHeader)); // Big Endian
    SwapBytes(RecordHeader.Nummer, SizeOf(RecordHeader.Nummer));
    SwapBytes(RecordHeader.Laenge, SizeOf(RecordHeader.Laenge));
    case FileHeader.ShapeType of
         1 : begin // Punkt - Shapefile
             Strom.Read(In_Punkt,SizeOf(In_Punkt));
             AddPoint(RecordHeader.Nummer, In_Punkt.X, In_Punkt.Y);
             end;

         3 : begin // PolyLine - Shapefile
             SetLength(PolyLinien,index);
             Strom.ReadBuffer(PLHead,SizeOf(PLHead));
             SetLength(PLContent.Parts,PLHead.NumParts);
             SetLength(PLContent.Points,PLHead.NumPoints);
             Strom.ReadBuffer(PLContent,SizeOf(PLContent));
             end;
    end;

  until (Strom.Position>=((FileHeader.FileLen)*2)); // da Filesize in Word =
                                              // 16-Bit = 2 Bytes angegeben wird
except
  error:=true;
  errmsg:='Fehler beim Einlesen der einzelnen Elemente bei ID : '+IntToStr(RecordHeader.Nummer);
  Strom.Free;
  exit;
end;
Strom.Free;
end;

procedure SwapBytes(Var Bytes; Len : Integer); // Vertauscht die Byte-Order
Var swapped : PChar; // Usage : SwapBytes(i,sizeof(i));
    i : Integer;
begin
 GetMem(swapped, Len);
 try
   for i:=0 to Len-1 do
       swapped[Len-i-1]:=PChar(@Bytes)[i];
   Move(swapped^, Bytes, Len);
 finally
   FreeMem(swapped);
 end;
end;

end.
Angehängte Dateien
Dateityp: zip meineLangePolyLine.shp.zip (307 Bytes, 5x aufgerufen)

Geändert von lagalex (19. Feb 2013 um 11:12 Uhr)
  Mit Zitat antworten Zitat