Advertisement
Guest User

UmbyNBT

a guest
Oct 1st, 2015
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; Named Binary Tag Reader
  2. ; By Umby24
  3. ; Written for the Hypercube Minecraft Server
  4. ; ##########################################
  5.  
  6. XIncludeFile "ZLib.pbi"
  7.  
  8. #NBTBufferSize = 67108864
  9. ;{ Enumerations
  10. Enumeration
  11.     #NBTCompressionNone
  12.     #NBTCompressionDetect
  13.     #NBTCompressionGZip
  14.     #NBTCompressionZlib
  15. EndEnumeration
  16.  
  17. Enumeration
  18.     #TAG_End
  19.     #TAG_Byte
  20.     #TAG_Short
  21.     #TAG_Int
  22.     #TAG_Long
  23.     #TAG_Float
  24.     #TAG_Double
  25.     #TAG_Byte_Array
  26.     #TAG_String
  27.     #TAG_List
  28.     #TAG_Compound
  29.     #TAG_Int_Array
  30. EndEnumeration
  31. ;}
  32. ;{ Structures
  33. Structure NBTTag
  34.     Name.s
  35.     Type.a
  36.    
  37.     RawSize.l
  38.     *RawData
  39.     *Parent.NBTTag
  40.    
  41.     Byte.b
  42.     Short.w
  43.     Int.l
  44.     Long.q
  45.     Float.f
  46.     Double.d
  47.     String.s
  48.    
  49.     ListType.a
  50.     ListLength.l
  51.    
  52.     List Children.NBTTag()
  53. EndStructure
  54. ;}
  55. ;{ Helping Assembly Functions
  56. Procedure.l Endian(val.l)
  57.     !MOV Eax,dword[p.v_val]
  58.     !BSWAP Eax
  59.     !MOV dword[p.v_val], Eax
  60.     ProcedureReturn val
  61. EndProcedure
  62.  
  63. Procedure.f EndianF(val.f)
  64.     !MOV Eax,dword[p.v_val]
  65.     !BSWAP Eax
  66.     !MOV dword[p.v_val], Eax
  67.     ProcedureReturn val
  68. EndProcedure
  69.  
  70. Procedure.w EndianW(val.w) ; Change Endianness of a Short (Word). Yay inline ASM!
  71.     !MOV ax, word[p.v_val]
  72.     !XCHG al, ah                ; Swap Lo byte <-> Hi byte
  73.     !MOV word[p.v_val], ax
  74.     ProcedureReturn val
  75. EndProcedure
  76.  
  77. Procedure.q EndianQ(val.q)
  78.     Protected Upper.l, Lower.l
  79.     ; Split the long into two 4 byte chunks (dwords)
  80.     PokeL(@Upper, PeekL(@val)) ; -- Upper = 1234
  81.     PokeL(@lower, PeekL(@Val + 4)) ; Lower = 5678
  82.    
  83.     !Mov Eax, dword[p.v_Upper] ; Moves one half into Eax  -- Eax = 1234
  84.     !Mov Ebx, dword[p.v_Lower] ; Moves the other half into Ebx -- Ebx = 5678
  85.     !BSwap Eax ; Swap the bytes in each ; = Eax = 4321
  86.     !BSwap Ebx ; - Ebx = 8765
  87.     !Mov dword[p.v_Upper], Eax ; Reassign the swapped values to their variables ; - Upper = 4321
  88.     !mov dword[p.v_Lower], Ebx ; - Lower = 8765
  89.    
  90.     PokeL(@Val, Lower) ; Push the new values, in reverse order, into the variable. ; - Val = 8765????
  91.     PokeL(@Val + 4, Upper) ; - Val = 87654321. Swap complete.
  92.     ProcedureReturn val
  93. EndProcedure
  94.  
  95. Procedure.d EndianD(val.d)
  96.     Protected Upper.l, Lower.l
  97.     ; Split the long into two 4 byte chunks (dwords)
  98.     PokeL(@Upper, PeekL(@val)) ; -- Upper = 1234
  99.     PokeL(@lower, PeekL(@Val + 4)) ; Lower = 5678
  100.    
  101.     !Mov Eax, dword[p.v_Upper] ; Moves one half into Eax  -- Eax = 1234
  102.     !Mov Ebx, dword[p.v_Lower] ; Moves the other half into Ebx -- Ebx = 5678
  103.     !BSwap Eax ; Swap the bytes in each ; = Eax = 4321
  104.     !BSwap Ebx ; - Ebx = 8765
  105.     !Mov dword[p.v_Upper], Eax ; Reassign the swapped values to their variables ; - Upper = 4321
  106.     !mov dword[p.v_Lower], Ebx ; - Lower = 8765
  107.    
  108.     PokeL(@Val, Lower) ; Push the new values, in reverse order, into the variable. ; - Val = 8765????
  109.     PokeL(@Val + 4, Upper) ; - Val = 87654321. Swap complete.
  110.     ProcedureReturn val
  111. EndProcedure
  112. ;}
  113. Global NbtTagHolder.NBTTag
  114. Declare NbtReadCompound(*Data, *DataOffset, *Tag.NBTTag)
  115. Declare NbtReadIntArray(*Data, *DataOffset, *Tag.NBTTag)
  116.  
  117. ;{ Reading Functions
  118. Procedure.b NbtReadByte(*Data, *DataOffset)
  119.     Protected Offset.l, Value.b
  120.    
  121.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  122.     Value = PeekB(*Data + Offset) ; Read the tag value..
  123.    
  124.     Offset + 1 ; Increase the offset by the size of the value
  125.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  126.    
  127.     ProcedureReturn Value ; And return the value.
  128. EndProcedure
  129.  
  130. Procedure.w NbtReadShort(*Data, *DataOffset)
  131.     Protected Offset.l, Value.w
  132.    
  133.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  134.     Value = EndianW(PeekW(*Data + Offset)) ; Read the tag value..
  135.    
  136.     Offset + 2 ; Increase the offset by the size of the value
  137.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  138.    
  139.     ProcedureReturn Value ; And return the value.
  140. EndProcedure
  141.  
  142. Procedure.l NbtReadInt(*Data, *DataOffset)
  143.     Protected Offset.l, Value.l
  144.    
  145.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  146.     Value = Endian(PeekL(*Data + Offset)) ; Read the tag value..
  147.    
  148.     Offset + 4 ; Increase the offset by the size of the value
  149.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  150.    
  151.     ProcedureReturn Value ; And return the value.
  152. EndProcedure
  153.  
  154. Procedure.q NbtReadLong(*Data, *DataOffset)
  155.     Protected Offset.l, Value.q
  156.    
  157.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  158.     Value = EndianQ(PeekQ(*Data + Offset)) ; Read the tag value..
  159.    
  160.     Offset + 8 ; Increase the offset by the size of the value
  161.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  162.    
  163.     ProcedureReturn Value ; And return the value.
  164. EndProcedure
  165.  
  166. Procedure.f NbtReadFloat(*Data, *DataOffset)
  167.     Protected Offset.l, Value.f
  168.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  169.     Value = EndianF(PeekF(*Data + Offset)) ; Read the tag value..
  170.    
  171.     Offset + 4 ; Increase the offset by the size of the value
  172.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  173.    
  174.     ProcedureReturn Value ; And return the value.
  175. EndProcedure
  176.  
  177. Procedure.d NbtReadDouble(*Data, *DataOffset)
  178.     Protected Offset.l, Value.d
  179.    
  180.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  181.     Value = EndianD(PeekD(*Data + Offset)) ; Read the tag value..
  182.    
  183.     Offset + 8 ; Increase the offset by the size of the value
  184.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  185.    
  186.     ProcedureReturn Value ; And return the value.
  187. EndProcedure
  188.  
  189. Procedure NbtReadByteArray(*Data, *DataOffset, *Tag.NBTTag)
  190.     Protected Offset.l, Size.l
  191.    
  192.     Size = NbtReadInt(*Data, *DataOffset)
  193.     Offset = PeekL(*DataOffset) ; Get the value of the offset..
  194.    
  195.     *Tag\RawData = AllocateMemory(Size)
  196.     *Tag\RawSize = Size
  197.     CopyMemory(*Data + Offset, *Tag\RawData, Size)
  198.    
  199.     Offset + Size
  200.     PokeL(*DataOffset, Offset) ; Push the new offset size to memory
  201. EndProcedure
  202.  
  203. Procedure.s NbtReadString(*Data, *DataOffset)
  204.     Protected Offset.l, Size.l, Value.s
  205.     Offset = PeekL(*DataOffset)
  206.    
  207.     Size = EndianW(PeekW(*Data + Offset))
  208.     Offset + 2
  209.     Value = PeekS(*Data + Offset, Size)
  210.     Offset + Size
  211.     PokeL(*DataOffset, Offset)
  212.    
  213.     ProcedureReturn Value
  214. EndProcedure
  215.  
  216. Procedure NbtReadList(*Data, *DataOffset, *Tag.NBTTag)
  217.     Protected Offset.l, Size.l, Type.l, i.l
  218.     Offset = PeekL(*DataOffset)
  219.     Type = PeekA(*Data + Offset)
  220.     Offset + 1
  221.     PokeL(*DataOffset, Offset)
  222.    
  223.     ; - Get list size.
  224.     Size = NbtReadInt(*Data, *DataOffset)
  225.     *Tag\ListType = Type
  226.     *Tag\ListLength = Size
  227.    
  228.     For i = 1 To Size ; Iterate the list.
  229.         Define *ChildElement.NBTTag = AddElement(*Tag\Children())
  230.         *Tag\Children()\Type = Type
  231.         *Tag\Children()\Name = "[None]"
  232.        
  233.         Select Type
  234.             Case #TAG_Byte
  235.                 *Tag\Children()\Byte = NbtReadByte(*Data, *DataOffset)
  236.             Case #TAG_Short
  237.                 *Tag\Children()\Short = NbtReadShort(*Data, *DataOffset)
  238.             Case #TAG_Int
  239.                 *Tag\Children()\Int = NbtReadInt(*Data, *DataOffset)
  240.             Case #TAG_Long
  241.                 *Tag\Children()\Long = NbtReadLong(*Data, *DataOffset)
  242.             Case #TAG_Float
  243.                 *Tag\Children()\Float = NbtReadFloat(*Data, *DataOffset)
  244.             Case #TAG_Double
  245.                 *Tag\Children()\Double = NbtReadDouble(*Data, *DataOffset)
  246.             Case #TAG_Byte_Array
  247.                 NbtReadByteArray(*Data, *DataOffset, *Tag\Children())
  248.             Case #TAG_String
  249.                 *Tag\Children()\String = NbtReadString(*Data, *DataOffset)
  250.             Case #TAG_List
  251.                 NbtReadList(*Data, *DataOffset, *ChildElement)
  252.             Case #TAG_Compound
  253.                 NbtReadCompound(*Data, *DataOffset, *ChildElement)
  254.             Case #TAG_Int_Array
  255.                 NbtReadIntArray(*Data, *DataOffset, *ChildElement)
  256.         EndSelect
  257.     Next
  258.    
  259. EndProcedure
  260.  
  261. Procedure NbtReadIntArray(*Data, *DataOffset, *Tag.NBTTag)
  262.     Protected Offset.l, Size.l, i.l, RawOffset.l
  263.     Size = NbtReadInt(*Data, *DataOffset)
  264.     ;Offset = PeekL(*DataOffset)
  265.    
  266.     *Tag\RawData = AllocateMemory(Size * 4)
  267.     *Tag\RawSize = Size
  268.    
  269.     For i = 1 To Size
  270.         ;PokeL(*DataOffset, Offset)
  271.         PokeL(*Tag\RawData + RawOffset, NbtReadInt(*Data, *DataOffset))
  272.         RawOffset + 4
  273.     Next
  274.    
  275. EndProcedure
  276.  
  277. Procedure NbtReadCompound(*Data, *DataOffset, *Tag.NBTTag)
  278.     Protected Offset.l
  279.     Offset = PeekL(*DataOffset)
  280.    
  281.     While 1=1
  282.         TagType.a = PeekA(*Data + Offset)
  283.         Offset+1
  284.        
  285.         If TagType <> #TAG_End
  286.             PokeL(*DataOffset, Offset)
  287.             AddElement(*Tag\Children())
  288.             *Tag\Children()\Type = TagType
  289.             *Tag\Children()\Name = NbtReadString(*Data, *DataOffset)
  290.             *Tag\Children()\Parent = *Tag
  291.         EndIf
  292.            
  293.         Select TagType
  294.             Case #TAG_End
  295.                 Break ; -- Break out of the reading loop.
  296.             Case #TAG_Byte
  297.                 *Tag\Children()\Byte = NbtReadByte(*Data, *DataOffset)
  298.             Case #TAG_Short
  299.                 *Tag\Children()\Short = NbtReadShort(*Data, *DataOffset)
  300.             Case #TAG_Int
  301.                 *Tag\Children()\Int = NbtReadInt(*Data, *DataOffset)
  302.             Case #TAG_Long
  303.                 *Tag\Children()\Long = NbtReadLong(*Data, *DataOffset)
  304.             Case #TAG_Float
  305.                 *Tag\Children()\Float = NbtReadFloat(*Data, *DataOffset)
  306.             Case #TAG_Double
  307.                 *Tag\Children()\Double = NbtReadDouble(*Data, *DataOffset)
  308.             Case #TAG_Byte_Array
  309.                 NbtReadByteArray(*Data, *DataOffset, *Tag\Children())
  310.             Case #TAG_String
  311.                 *Tag\Children()\String = NbtReadString(*Data, *DataOffset)
  312.             Case #TAG_List
  313.                 NbtReadList(*Data, *DataOffset, *Tag\Children())
  314.             Case #TAG_Compound
  315.                 NbtReadCompound(*Data, *DataOffset, *Tag\Children())
  316.             Case #TAG_Int_Array
  317.                 NbtReadIntArray(*Data, *DataOffset, *Tag\Children())
  318.         EndSelect
  319.        
  320.         Offset = PeekL(*DataOffset)
  321.     Wend
  322.    
  323.     PokeL(*DataOffset, Offset)
  324. EndProcedure
  325.  
  326. Procedure ParseNbtData(*YourTag.NBTTag, *Data, Datalength)
  327.     Define Offset.l
  328.    
  329.     TagType.a = PeekA(*Data + Offset)
  330.     Offset+1
  331.    
  332.     If TagType <> #TAG_Compound
  333.         PrintN("Compound tag not the base.")
  334.         ProcedureReturn
  335.     EndIf
  336.    
  337.     *YourTag\Type = TagType
  338.     *YourTag\Name = NbtReadString(*Data, @Offset)
  339.     NbtReadCompound(*Data, @Offset, *YourTag)
  340. EndProcedure
  341.  
  342. Procedure DecompressData(*Data, DataLength)
  343.     Protected Stream.z_stream, BufferSize
  344.    
  345.     BufferSize = #NBTBufferSize
  346.     *Temp = AllocateMemory(BufferSize)
  347.    
  348.     Stream\avail_in = DataLength
  349.     Stream\avail_out = BufferSize
  350.     Stream\next_in = *Data
  351.     Stream\next_out = *Temp
  352.    
  353.     If Not inflateInit2_(@Stream, 47, zlibVersion(), SizeOf(z_stream)) = #Z_OK
  354.         FreeMemory(*Temp)
  355.         ProcedureReturn #Null
  356.     EndIf
  357.    
  358.     Repeat
  359.         TempResult = inflate(Stream, #Z_NO_FLUSH)
  360.        
  361.         If TempResult <> #Z_OK And TempResult <> #Z_STREAM_END
  362.             FreeMemory(*Temp)
  363.             inflateEnd(Stream)
  364.             ProcedureReturn #Null
  365.         EndIf
  366.        
  367.         If TempResult = #Z_OK
  368.             BufferSize + #NBTBufferSize
  369.             *Temp = ReAllocateMemory(*Temp, BufferSize)
  370.            
  371.             Stream\avail_out = #NBTBufferSize
  372.             Stream\next_out = *Temp + BufferSize - #NBTBufferSize
  373.         EndIf
  374.     Until TempResult = #Z_STREAM_END
  375.    
  376.     inflateEnd(Stream)
  377.    
  378.     ProcedureReturn *Temp
  379. EndProcedure
  380.  
  381. Procedure ParseNBT(*Data, DataLength, CompressionMode)
  382.     ; This file will first decompress the data (if need be) then pass it off for real parsing, and then return it.    
  383.     Select CompressionMode
  384.         Case #NBTCompressionNone
  385.             ParseNbtData(@NbtTagHolder, *Data, DataLength)
  386.             FreeMemory(*Data)
  387.         Case #NBTCompressionDetect
  388.             If PeekA(*Data) = $1F And PeekA(*Data + 1) = $8B
  389.                 ; Compressed. Need to decompress.
  390.                 *Uncompressed = DecompressData(*Data, DataLength)
  391.                 ; We can now free our compressed data from memory, it is no longer needed.
  392.                 FreeMemory(*Data)
  393.                
  394.                 If *Uncompressed <> #Null
  395.                     ParseNbtData(@NbtTagHolder, *Uncompressed, MemorySize(*Uncompressed))
  396.                     FreeMemory(*Uncompressed)
  397.                 EndIf
  398.                
  399.             Else
  400.                 ParseNbtData(@NbtTagHolder, *Data, DataLength)
  401.                 FreeMemory(*Data)
  402.             EndIf
  403.         Case #NBTCompressionGZip, #NBTCompressionZlib
  404.             *Uncompressed = DecompressData(*Data, DataLength)
  405.             ; We can now free our compressed data from memory, it is no longer needed.
  406.             FreeMemory(*Data)
  407.            
  408.             If *Uncompressed <> #Null
  409.                 ParseNbtData(@NbtTagHolder, *Uncompressed, MemorySize(*Uncompressed))
  410.             EndIf
  411.            
  412.             FreeMemory(*Uncompressed)
  413.     EndSelect
  414.    
  415.     ProcedureReturn @NbtTagHolder
  416. EndProcedure
  417.  
  418. Procedure ReadNBTFile(Filename.s, CompressionMode=#NBTCompressionDetect)
  419.     Protected FileID, *FileBuffer
  420.    
  421.     FileID = OpenFile(#PB_Any, Filename)
  422.    
  423.     If Not FileID
  424.         ProcedureReturn ; Couldn't open file.
  425.     EndIf
  426.    
  427.     *FileBuffer = AllocateMemory(Lof(FileID))
  428.    
  429.     If Not *FileBuffer
  430.         CloseFile(FileID)
  431.         ProcedureReturn ; Failed to allocate memory
  432.     EndIf
  433.    
  434.     If ReadData(FileID, *FileBuffer, Lof(FileID)) <> Lof(FileID)
  435.         CloseFile(FileID)
  436.         FreeMemory(*FileBuffer)
  437.         ProcedureReturn
  438.     EndIf
  439.    
  440.     CloseFile(FileID)
  441.    
  442.     ProcedureReturn ParseNBT(*FileBuffer, MemorySize(*FileBuffer), CompressionMode)
  443. EndProcedure
  444. ;}
  445. ;{ Saving Functions
  446. Procedure GetNBTSize(*Tag.NBTTag)
  447.     Protected Size.l
  448.    
  449.     If Not *Tag
  450.         ProcedureReturn #False
  451.     EndIf
  452.    
  453.     If Not (*Tag\Parent And *Tag\Parent\Type = #TAG_List)
  454.         Size + 3 + StringByteLength(*Tag\Name, #PB_UTF8)
  455.     EndIf
  456.    
  457.     ;Get payload size
  458.     Select *Tag\Type
  459.         Case #TAG_Byte : Size + 1
  460.         Case #TAG_Short : Size + 2
  461.         Case #TAG_Int : Size + 4
  462.         Case #TAG_Long : Size + 8
  463.         Case #TAG_Float : Size + 4
  464.         Case #TAG_Double : Size + 8
  465.         Case #TAG_Byte_Array : Size + 4 + *Tag\RawSize
  466.         Case #TAG_String : Size + 2 + StringByteLength(*Tag\String, #PB_UTF8)
  467.         Case #TAG_List
  468.             Size + 5 ;Type and list size.
  469.            
  470.             ForEach *Tag\Children()
  471.                 Size + GetNBTSize(*Tag\Children())
  472.             Next
  473.         Case #TAG_Compound
  474.             ForEach *Tag\Children()
  475.                 Size + GetNBTSize(*Tag\Children())
  476.             Next
  477.             Size + 1 ; Tag_End
  478.         Case #TAG_Int_Array : Size + 4 + (*Tag\RawSize * 4)
  479.     EndSelect
  480.    
  481.     ProcedureReturn Size
  482. EndProcedure
  483. ;
  484. Procedure SaveNBT(*Tag.NBTTag, *Memory)
  485.     If Not *Tag
  486.         ProcedureReturn #False
  487.     EndIf
  488.    
  489.     If Not *Memory
  490.         ProcedureReturn #False
  491.     EndIf
  492.    
  493.     If Not (*Tag\Parent And *Tag\Parent\Type = #TAG_List)
  494.         PokeB(*Memory, *Tag\Type) : *Memory + 1 ; Tag Type
  495.         PokeW(*Memory, EndianW(StringByteLength(*Tag\Name, #PB_UTF8))) : *Memory + 2 ; Length of name
  496.         PokeS(*Memory, *Tag\Name, -1, #PB_UTF8) : *Memory + StringByteLength(*Tag\Name, #PB_UTF8) ; The actual name
  497.     EndIf
  498.    
  499.     ;Get payload size
  500.     Select *Tag\Type
  501.         Case #TAG_Byte
  502.             PokeB(*Memory, *Tag\Byte)
  503.             *Memory + 1
  504.         Case #TAG_Short
  505.             PokeW(*Memory, EndianW(*Tag\Short))
  506.             *Memory + 2
  507.         Case #TAG_Int
  508.             PokeL(*Memory, Endian(*Tag\Int))
  509.             *Memory + 4
  510.         Case #TAG_Long
  511.             PokeQ(*Memory, EndianQ(*Tag\Long))
  512.             *Memory + 8
  513.         Case #TAG_Float
  514.             PokeF(*Memory, EndianF(*Tag\Float))
  515.             *Memory + 4
  516.         Case #TAG_Double
  517.             PokeD(*Memory, EndianD(*Tag\Double))
  518.             *Memory + 8
  519.         Case #TAG_Byte_Array
  520.             PokeL(*Memory, Endian(*Tag\RawSize))
  521.             *Memory + 4
  522.            
  523.             If *Tag\RawData
  524.                 CopyMemory(*Tag\RawData, *Memory, *Tag\RawSize)
  525.             EndIf
  526.            
  527.             *Memory + *Tag\RawSize
  528.         Case #TAG_String
  529.             PokeW(*Memory, EndianW(*Tag\RawSize))
  530.             *Memory + 2
  531.            
  532.             PokeS(*Memory, *Tag\String, -1, #PB_UTF8)
  533.             *Memory + *Tag\RawSize
  534.         Case #TAG_List
  535.             PokeB(*Memory, *Tag\ListType) : *Memory + 1
  536.             PokeL(*Memory, Endian(*Tag\ListLength))
  537.             *Memory + 4
  538.            
  539.             ForEach *Tag\Children()
  540.                 *Memory = SaveNBT(*Tag\Children(), *Memory)
  541.             Next
  542.            
  543.         Case #TAG_Compound
  544.             ForEach *Tag\Children()
  545.                 *Memory = SaveNBT(*Tag\Children(), *Memory)
  546.             Next
  547.            
  548.             PokeB(*Memory, 0) : *Memory + 1
  549.         Case #TAG_Int_Array
  550.             PokeL(*Memory, Endian(*Tag\RawSize)) : *Memory + 4
  551.             Define i.l, offset.l
  552.             offset = 0
  553.            
  554.             For i = 1 To *Tag\RawSize
  555.                 PokeL(*Memory, Endian(PeekL(*Tag\RawData + offset)))
  556.                 *Memory + 4
  557.                 offset + 4
  558.             Next
  559.            
  560.             *Memory + (*Tag\RawSize * 4)
  561.     EndSelect
  562.    
  563.     ProcedureReturn *Memory
  564. EndProcedure
  565. ;
  566. Procedure SaveNBTFile(*NBT.NBTTag, Filename.s, CompressionMode=#NBTCompressionGZip)
  567.     Protected File.l, *NbtMem, NbtSize.l
  568.    
  569.     If Not *NBT
  570.         ProcedureReturn #False
  571.     EndIf
  572.    
  573.     File = CreateFile(#PB_Any, Filename)
  574.    
  575.     If Not File
  576.         ProcedureReturn #False
  577.     EndIf
  578.    
  579.     NbtSize = GetNBTSize(*NBT)
  580.     *NbtMem = AllocateMemory(NbtSize)
  581.    
  582.     PrintN(Str(NbtSize))
  583.     PrintN(Str(*NbtMem))
  584.    
  585.     If Not *NbtMem
  586.         CloseFile(File)
  587.         ProcedureReturn #False
  588.     EndIf
  589.    
  590.     SaveNBT(*NBT, *NbtMem)
  591.    
  592.     Select CompressionMode
  593.         Case #NBTCompressionNone
  594.             WriteData(File, *NbtMem, NbtSize)
  595.         Case #NBTCompressionGZip
  596.         Case #NBTCompressionZlib
  597.     EndSelect
  598.    
  599.     CloseFile(File)
  600.     ProcedureReturn #True
  601. EndProcedure
  602.  
  603. ;}
  604. ;{ Manipulation Functions
  605. Procedure AddTag(*Tag.NBTTag, TagType, TagName)
  606. ;}
  607. ;{ Serialization to string
  608. Procedure.s SerializeNbt(*Tag.NBTTag, Level=0)
  609.     Protected Output.s = Space(Level*4)
  610.    
  611.     If Not *Tag
  612.         ProcedureReturn "[Invalid_Element]"
  613.     EndIf
  614.    
  615.     Select *Tag\Type
  616.         Case #TAG_End
  617.             Output + "[This shouldn't appear!]"
  618.         Case #TAG_Byte
  619.             Output + "TAG_Byte('"+*Tag\Name+"'): "+Str(*Tag\Byte)
  620.         Case #Tag_Short
  621.             Output + "TAG_Short('"+*Tag\Name+"'): "+Str(*Tag\Short)
  622.         Case #TAG_Int
  623.             Output + "TAG_Int('"+*Tag\Name+"'): "+Str(*Tag\Int)
  624.         Case #TAG_Long
  625.             Output + "TAG_Long('"+*Tag\Name+"'): "+Str(*Tag\Long)
  626.         Case #TAG_Float
  627.             Output + "TAG_Float('"+*Tag\Name+"'): "+StrF(*Tag\Float)
  628.         Case #TAG_Double
  629.             Output + "TAG_Double('"+*Tag\Name+"'): "+StrD(*Tag\Double)
  630.         Case #Tag_Byte_Array
  631.             Output + "TAG_Byte_Array('"+*Tag\Name+"'): ["+Str(*Tag\RawSize)+" bytes]"
  632.         Case #Tag_String
  633.             Output + "TAG_String('"+*Tag\Name+"'): '"+*Tag\String+"'"
  634.         Case #Tag_List
  635.             Output + "TAG_List('"+*Tag\Name+"'): "+Str(ListSize(*Tag\Children()))+" entries" + #CRLF$
  636.             Output + Space(Level*4) + "{" + #CRLF$
  637.            
  638.             ForEach *Tag\Children()
  639.                 Output + SerializeNbt(*Tag\Children(), Level+1) + #CRLF$
  640.             Next
  641.            
  642.             Output + Space(Level*4) + "}"
  643.         Case #Tag_Compound
  644.             Output + "TAG_Compound('"+*Tag\Name+"'): "+Str(ListSize(*Tag\Children()))+" entries" + #CRLF$
  645.             Output + Space(Level*4) + "{" + #CRLF$
  646.            
  647.             ForEach *Tag\Children()
  648.                 Output + SerializeNbt(*Tag\Children(), Level+1) + #CRLF$
  649.             Next
  650.            
  651.             Output + Space(Level*4) + "}"
  652.         Case #Tag_Int_Array
  653.             Output + "TAG_Int_Array('"+*Tag\Name+"'): ["+Str(*Tag\RawSize)+" ints]"
  654.         Default
  655.             Output + "[Something went really wrong here!]"
  656.     EndSelect
  657.    
  658.     ProcedureReturn Output
  659. EndProcedure
  660.  
  661. ;}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement