1 /++
2     A module for creating chunks. You can put any data in it, and compress, 
3     and extract the very chunks from files. It will be useful for storing 
4     some kind of data about maps, textures or the like.
5 
6     ---
7     Chunk chunk = Chunk("Simple chunk", "Hello, World! It's Chunk!");
8     std.file.write("binary",chunk.save());
9     ---
10 
11     Authors: TodNaz
12     License: MIT
13 +/
14 module chunkd.chunk;
15 
16 import std.zlib;
17 
18 private ubyte[4] toByte(T)(T value) @trusted
19 {
20     ubyte[4] ab;
21     for (int i = 0; i < 4; i++)
22         ab[3 - i] = cast(ubyte) (value >> (i * 8));
23 
24     return ab;
25 }
26 
27 private T byteTo(T)(ubyte[] bytes) @trusted
28 {
29     T data = T.init;
30     foreach(i; 0 .. bytes.length) data |= cast(T) ((data << 8) + bytes[i]);
31 
32     return data;
33 }
34 
35 /++
36     Chunk structure. Has a title and information. The size of the chunk, the size 
37     of the name, then the name itself and the data are written to the file, and 
38     so on in order.
39 +/
40 struct Chunk
41 {
42     public
43     {
44         string name; /// Chunk name
45         ubyte[] data; /// Chunk data
46     }
47 
48     /++
49         Creates a chunk.
50 
51         Params:
52             name = Chunk name.
53             data = Chunk data.
54     +/
55     this(string name,ubyte[] data) @safe
56     {
57         this.name = name;
58         this.data = data;
59     }
60 
61     /// ditto
62     this(string name,string data) @trusted
63     {
64         this.name = name;
65         this.data = cast(ubyte[]) data;
66     }
67 
68     ///
69     public string toString() @trusted
70     {
71         return "Chunk(\""~name~"\",\""~(cast(string) data)~"\")";
72     }
73 
74     /++
75         Compresses data. They are extremely effective only in large quantities.
76     +/
77     public Chunk compress() @trusted
78     {
79         data = std.zlib.compress(cast(void[]) data);
80 
81         return this;
82     }
83 
84     /++
85         Decompress data if it has been compressed.
86     +/
87     public Chunk uncompress() @trusted
88     {
89         data = cast(ubyte[]) std.zlib.uncompress(cast(void[]) data, 0u, HeaderFormat.deflate);
90 
91         return this;
92     }
93 
94     /++
95         Gives the size of the data.
96     +/
97     public size_t size() @safe
98     {
99         return data.length * ubyte.sizeof;
100     }
101 
102     /++
103         Gives exhaust in the form of bytes, where you can write to a file, 
104         from where, in the future, you can parse chunks.
105     +/
106     public ubyte[] save() @trusted
107     {
108         return size().toByte ~ (name.length * ubyte.sizeof).toByte ~ (cast(ubyte[]) name) ~ data;
109     }
110 
111     /++
112         Retrieves chunks from file data or other information storage location
113 
114         Params:
115             data = Data.
116     +/
117     public static Chunk[] parse(ubyte[] data) @trusted
118     {
119         Chunk[] chunks;
120 
121         size_t i = 0;
122         size_t lenName;
123         size_t lenData;
124         string _name;
125         ubyte[] _data;
126 
127         while(i < data.length) {
128             lenData = byteTo!size_t(data[i .. i + 4])     / ubyte.sizeof;
129             lenName = byteTo!size_t(data[i + 4 .. i + 8]) / ubyte.sizeof;
130 
131             _name = cast(string) data[i + 8 .. i + 8 + lenName];
132             _data = data[i + 8 + lenName .. i + 8 + lenName + lenData];
133 
134             chunks ~= Chunk(_name,_data);
135 
136             i = i + 8 + lenName + lenData;
137         }
138 
139         return chunks;
140     }
141 }
142 
143 @("Chunk test") @safe
144 unittest
145 {
146     Chunk chunk = Chunk("Simple", "Hello, World!");
147 
148     ubyte[] data = chunk.save();
149 
150     assert(Chunk.parse(data)[0] == chunk);
151 }
152 
153 @("Chunk compress") @safe
154 unittest
155 {
156     Chunk chunk = Chunk("Test","
157         MIT License
158 
159         Permission is hereby granted, free of charge, to any person obtaining a copy of 
160         this software and associated documentation files (the \"Software\"), to deal in the 
161         Software without restriction, including without limitation the rights to use, copy, 
162         modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
163         and to permit persons to whom the Software is furnished to do so, subject to the 
164         following conditions:
165 
166         The above copyright notice and this permission notice shall be included in all copies 
167         or substantial portions of the Software.
168 
169         THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
170         INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
171         PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
172         FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
173         OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
174         OTHER DEALINGS IN THE SOFTWARE.
175 
176         ...");
177 
178     chunk.compress();
179 
180     ubyte[] data = chunk.save();
181 
182     chunk.uncompress();
183 
184     assert(Chunk.parse(data)[0].uncompress() == chunk);
185 }