├── .gitignore
├── LICENSE
├── README.md
├── assets
└── DSStore-clean
├── index.js
├── lib
├── buddy-allocator.js
├── ds-store.js
├── entry.js
└── partition.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Linus Unnebäck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-ds-store
2 |
3 | .DS_Store manipulation and creation from node.js
4 |
5 | ## Status
6 |
7 | Currently the implementation uses a pre-created `.DS_Store` file
8 | which it then modifies to suit the needs. This places several
9 | limitations and also only allows creating new files from scratch.
10 |
11 | ## Installation
12 |
13 | ```sh
14 | npm install ds-store
15 | ```
16 |
17 | ## Usage
18 |
19 | ```javscript
20 | var DSStore = require('ds-store');
21 |
22 | var file = new DSStore();
23 | ```
24 |
25 | ## API
26 |
27 | ### file.setBackgroundPath(path)
28 |
29 | Set the background image to file specified by `path`.
30 |
31 | ### file.setBackgroundColor(red, green, blue)
32 |
33 | Set the background color to the color specified by three floats between 0 and 1.
34 |
35 | ### file.setIconSize(size)
36 |
37 | Set the size of all icons in the folder to `size`.
38 |
39 | ### file.setIconPos(name, x, y)
40 |
41 | Position a file icon for file named `name` at `x, y`.
42 |
43 | ### file.setWindowPos(x, y)
44 |
45 | Set the Finder window position to `x, y`.
46 |
47 | ### file.setWindowSize(w, h)
48 |
49 | Set the Finder window size to `w, h`.
50 |
51 | ### file.vSrn(value)
52 |
53 | Set the `vSrn` value to either `0` or `1`.
54 |
55 | Effect currently unknown.
56 |
57 | ### file.write(path, cb)
58 |
59 | Write the `.DS_Store` information to file at `path`.
60 |
61 | `cb` will get called with `err` upon file creation.
62 |
63 | ## Future
64 |
65 | I have started work on a Buddy Allocator and B-Tree implementation,
66 | but there is still lots of work required. Having theese would make
67 | it easy to both read and manipulate files. It also wouldn't require
68 | shipping a `DSStore-clean` file.
69 |
70 | ## Thanks
71 |
72 | A special thanks to Wim Lewis who have written a complete implementation
73 | in perl. His documentation of the file format helped me very much.
74 |
75 | http://search.cpan.org/~wiml/Mac-Finder-DSStore/DSStoreFormat.pod
76 |
--------------------------------------------------------------------------------
/assets/DSStore-clean:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinusU/node-ds-store/75b91d6cb6ee9b20012f3aae0dcff7f4ff990d12/assets/DSStore-clean
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 | var alias = require('macos-alias')
3 | var util = require('util')
4 |
5 | var Entry = require('./lib/entry')
6 | var DSStore = require('./lib/ds-store')
7 |
8 | function Helper () {
9 | this.file = new DSStore()
10 | this.opts = {
11 | window: { x: 100, y: 100 }
12 | }
13 | }
14 |
15 | Helper.prototype.setBackgroundPath = function (path) {
16 | this.opts.backgroundPath = path
17 | }
18 |
19 | Helper.prototype.setBackgroundColor = function (red, green, blue) {
20 | this.opts.backgroundColor = [red, green, blue]
21 | }
22 |
23 | Helper.prototype.setIconSize = function (size) {
24 | this.opts.iconSize = size
25 | }
26 |
27 | Helper.prototype.setIconPos = function (name, x, y) {
28 | this.file.push(Entry.construct(name, 'Iloc', { x: x, y: y }))
29 | }
30 |
31 | Helper.prototype.setWindowPos = function (x, y) {
32 | this.opts.window.x = x
33 | this.opts.window.y = y
34 | }
35 |
36 | Helper.prototype.setWindowSize = function (w, h) {
37 | this.opts.window.width = w
38 | this.opts.window.height = h + 22
39 | }
40 |
41 | Helper.prototype.vSrn = function (value) {
42 | assert(value === 0 || value === 1)
43 | this.file.push(Entry.construct('.', 'vSrn', { value: value }))
44 | }
45 |
46 | Helper.prototype.write = function (path, cb) {
47 | var rawAlias, colorComponents
48 |
49 | if (this.opts.backgroundPath) {
50 | rawAlias = alias.create(this.opts.backgroundPath)
51 | }
52 |
53 | if (this.opts.backgroundColor) {
54 | colorComponents = this.opts.backgroundColor
55 | }
56 |
57 | this.file.push(Entry.construct('.', 'bwsp', this.opts.window))
58 | this.file.push(Entry.construct('.', 'icvp', { iconSize: this.opts.iconSize, rawAlias: rawAlias, colorComponents: colorComponents }))
59 |
60 | this.file.write(path, cb)
61 | }
62 |
63 | /* Backwards compatibility */
64 | Helper.prototype.setBackground = util.deprecate(
65 | Helper.prototype.setBackgroundPath,
66 | 'setBackground is deprecated, please use setBackgroundPath'
67 | )
68 |
69 | module.exports = exports = Helper
70 |
--------------------------------------------------------------------------------
/lib/buddy-allocator.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 |
3 | function BuddyAllocator () {
4 | this.offsets = new Array(0)
5 | this.freelist = new Array(32)
6 |
7 | for (var i = 0; i < 32; i++) {
8 | this.freelist[i] = []
9 | }
10 |
11 | this.freelist[31].push(0)
12 |
13 | var head = this._alloc(5)
14 | assert(head === 0)
15 | }
16 |
17 | BuddyAllocator.prototype._alloc = function (width) {
18 | assert(width < 32)
19 |
20 | var list = this.freelist[width]
21 |
22 | if (list.length > 0) {
23 | // There is a block of the desired size; return it.
24 |
25 | return list.shift()
26 | } else {
27 | // Allocate a block of the next larger size; split
28 | // it and put the other half on the free list.
29 |
30 | var offset = this._alloc(width + 1)
31 | var buddy = offset ^ Math.pow(2, width)
32 |
33 | this._free(buddy, width)
34 | return offset
35 | }
36 | }
37 |
38 | BuddyAllocator.prototype._free = function (offset, width) {
39 | var list = this.freelist[width]
40 | var buddy = offset ^ Math.pow(2, width)
41 |
42 | var idx = list.indexOf(buddy)
43 |
44 | if (~idx) {
45 | // Our buddy is free. Coalesce, and
46 | // add the coalesced block to freelist.
47 |
48 | list.splice(idx, 1)
49 | this._free(offset & buddy, width + 1)
50 | } else {
51 | // Add this block to the freelist
52 |
53 | list.push(offset)
54 | // FIXME: maybe sort the list as well
55 | }
56 | }
57 |
58 | BuddyAllocator.prototype.allocate = function (bytes, blocknum) {
59 | if (blocknum === undefined) {
60 | blocknum = 1
61 |
62 | while (this.offsets[blocknum] !== undefined) {
63 | blocknum += 1
64 | }
65 | }
66 |
67 | var wantwidth = 5
68 | while (bytes > (1 << wantwidth)) {
69 | wantwidth += 1
70 | }
71 |
72 | var blockaddr, blockwidth, blockoffset
73 | if (this.offsets[blocknum]) {
74 | blockaddr = this.offsets[blocknum]
75 | blockwidth = blockaddr & 0x1F
76 | blockoffset = blockaddr & ~0x1F
77 | if (blockwidth === wantwidth) {
78 | return blocknum
79 | } else {
80 | this._free(blockoffset, blockwidth)
81 | delete this.offsets[blocknum]
82 | }
83 | }
84 |
85 | blockoffset = this._alloc(wantwidth)
86 | blockaddr = blockoffset | wantwidth
87 | this.offsets[blocknum] = blockaddr
88 |
89 | return blocknum
90 | }
91 |
92 | module.exports = exports = BuddyAllocator
93 |
--------------------------------------------------------------------------------
/lib/ds-store.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs')
2 | var path = require('path')
3 | // var assert = require('assert')
4 |
5 | var Entry = require('./entry')
6 | // var partition = require('./partition')
7 | // var BuddyAllocator = require('./buddy-allocator')
8 |
9 | function DSStore () {
10 | this.entries = []
11 | // this.store = new BuddyAllocator()
12 | }
13 |
14 | DSStore.prototype.push = function (entry) {
15 | this.entries.push(entry)
16 | }
17 |
18 | // DSStore.prototype._header = function (offset, size) {
19 | // var header = new Buffer(32)
20 | //
21 | // // header.writeUInt32BE(1, 0) Appears before header, eg. not part of it
22 | // header.write('Bud1', 0, 'ascii')
23 | //
24 | // header.writeUInt32BE(offset, 4)
25 | // header.writeUInt32BE(size, 8)
26 | // header.writeUInt32BE(offset, 12)
27 | //
28 | // header.writeUInt32BE(0x100C, 16)
29 | // header.writeUInt32BE(0x0000, 20) // 0x0087
30 | // header.writeUInt32BE(0x0000, 24) // 0x200B
31 | // header.writeUInt32BE(0x0000, 28)
32 | //
33 | // return header
34 | // }
35 | //
36 | // DSStore.prototype._entries = function () {
37 | // var tocblock
38 | // var pagesize = 0x1000
39 | //
40 | // if ('DSDB' in this.store.toc) {
41 | // throw new Error('Not implemented')
42 | // }
43 | //
44 | // tocblock = this.store.allocate(20)
45 | // this.store.toc['DSDB'] = tocblock
46 | //
47 | // var pagecount, reccount, height, children
48 | //
49 | // reccount = this.entries.length
50 | // pagecount = 0
51 | // height = 0
52 | // children = []
53 | //
54 | // do {
55 | // var sizes
56 | //
57 | // if (children.length > 0) {
58 | // sizes = this.entries.map(function (e) { return 4 + e.length() })
59 | // } else {
60 | // sizes = this.entries.map(function (e) { return e.length() })
61 | // }
62 | //
63 | // var interleaf = partition.sizes(pagesize - 8, sizes)
64 | // var nchildren = []
65 | // var next = 0
66 | //
67 | // throw new Error('Not implemented')
68 | // } while (children.length > 1)
69 | // }
70 |
71 | // sub putDSDBEntries {
72 | // my(@children);
73 |
74 | // # Partition the records into btree nodes, from the bottom of
75 | // # the tree working towards the root.
76 | // do {
77 | // my(@sizes);
78 |
79 | // if (@children) {
80 | // # Interior node: child pointers interleaved with records
81 | // @sizes = map { 4 + $_->byteSize } @$recs;
82 | // } else {
83 | // # Leaf node: just a bunch of records
84 | // @sizes = map { $_->byteSize } @$recs;
85 | // }
86 |
87 | // # In addition to @sizes, each page contains a record
88 | // # count and a flag/childnode field (4 bytes each)
89 | // my(@interleaf) = &partition_sizes($pagesize - 8, @sizes);
90 | // my(@nchildren);
91 |
92 | // my($next) = 0;
93 | // foreach my $non (@interleaf, 1+$#$recs) {
94 | // my($blknr) = $file->allocate($pagesize);
95 | // push(@nchildren, $blknr);
96 | // my($blk) = $file->blockByNumber($blknr, 1);
97 | // if (@children) {
98 | // &writeBTreeNode($blk,
99 | // [ @$recs[ $next .. $non-1 ] ],
100 | // [ @children[ $next .. $non ] ] );
101 | // } else {
102 | // &writeBTreeNode($blk,
103 | // [ @$recs[ $next .. $non-1 ] ]);
104 | // }
105 | // $blk->close(1);
106 | // $next = $non + 1;
107 | // $pagecount ++;
108 | // }
109 |
110 | // $height ++;
111 | // $recs = [ map { $recs->[$_] } @interleaf ];
112 | // @children = @nchildren;
113 | // die unless @children == 1+@$recs;
114 | // } while(@children > 1);
115 | // die unless 0 == @$recs;
116 |
117 | // my($masterblock) = $file->blockByNumber($tocblock, 1);
118 | // $masterblock->write('NNNNN',
119 | // $children[0],
120 | // $height - 1,
121 | // $reccount,
122 | // $pagecount,
123 | // $pagesize);
124 | // $masterblock->close;
125 |
126 | // 1;
127 | // }
128 | //
129 | // DSStore.prototype.__REAL__write = function (filePath) {
130 | // var store = new Buffer(15360)
131 | // var offset = 8192
132 | // var size = 2048
133 | // var currentPos = 0
134 | //
135 | // store.fill(0)
136 | //
137 | // this._header(offset, size).copy(store, currentPos)
138 | // currentPos += 32
139 | //
140 | // var blockAddresses = [
141 | // 0x0000200B,
142 | // 0x00000045,
143 | // 0x0000100C
144 | // ]
145 | //
146 | // currentPos = offset
147 | // store.writeUInt32BE(blockAddresses.length, currentPos)
148 | // store.writeUInt32BE(0, currentPos + 4)
149 | //
150 | // currentPos += 8
151 | //
152 | // store.fill(0, currentPos, currentPos + (256 * 4))
153 | //
154 | // blockAddresses.forEach(function (e, i) {
155 | // store.writeUInt32BE(e, currentPos + (i * 4))
156 | // })
157 | //
158 | // currentPos += (256 * 4)
159 | //
160 | // var directoryEntries = [
161 | // 'DSDB'
162 | // ]
163 | //
164 | // store.writeUInt32BE(directoryEntries.length, currentPos)
165 | // currentPos += 4
166 | //
167 | // directoryEntries.forEach(function (e, i) {
168 | // var b = new Buffer(e, 'ascii')
169 | // store.writeUInt8(b.length, currentPos)
170 | // b.copy(store, currentPos + 1)
171 | // store.writeUInt32BE(i + 1, currentPos + 1 + b.length)
172 | // currentPos += 1 + b.length + 4
173 | // })
174 | //
175 | // var freeList = [
176 | // [],
177 | // [],
178 | // [],
179 | // [],
180 | // [],
181 | // [32, 96],
182 | // [],
183 | // [128],
184 | // [256],
185 | // [512],
186 | // [1024],
187 | // [2048, 10240],
188 | // [12288],
189 | // [],
190 | // [16384],
191 | // [32768],
192 | // [65536],
193 | // [131072],
194 | // [262144],
195 | // [524288],
196 | // [1048576],
197 | // [2097152],
198 | // [4194304],
199 | // [8388608],
200 | // [16777216],
201 | // [33554432],
202 | // [67108864],
203 | // [134217728],
204 | // [268435456],
205 | // [536870912],
206 | // [1073741824],
207 | // []
208 | // ]
209 | //
210 | // assert(freeList.length === 32)
211 | // assert(freeList[31].length === 0)
212 | //
213 | // freeList.forEach(function (e) {
214 | // store.writeUInt32BE(e.length, currentPos)
215 | // e.forEach(function (e, i) {
216 | // store.writeUInt32BE(e, currentPos + 4 + (i * 4))
217 | // })
218 | // currentPos += 4 + (e.length * 4)
219 | // })
220 | //
221 | // /*
222 | // * Maybe jump to blockAddresses[0] (+- 4/8 bytes) and write something like:
223 | // *
224 | // * 00 00 20 0B
225 | // * 00 00 00 45
226 | // * 00 00 10 0C
227 | // * 00 00 00 00
228 | // *
229 | // */
230 | //
231 | // //
232 | //
233 | // var entries = this.entries.sort(Entry.sort);
234 | //
235 | // // should have something to do with blockAddresses[2]
236 | // [4096].forEach(function (e) {
237 | // currentPos = e
238 | //
239 | // var P = 0
240 | // var count = entries.length
241 | //
242 | // store.writeUInt32BE(P, currentPos)
243 | // store.writeUInt32BE(count, currentPos + 4)
244 | // currentPos += 8
245 | //
246 | // entries.forEach(function (e, i) {
247 | // e.buffer.copy(store, currentPos)
248 | // currentPos += e.buffer.length
249 | // })
250 | // })
251 | //
252 | // //
253 | //
254 | // var out = fs.createWriteStream(filePath)
255 | //
256 | // out.write(new Buffer('00000001', 'hex'))
257 | // out.write(store)
258 | //
259 | // out.end()
260 | // }
261 |
262 | DSStore.prototype.write = function (filePath, cb) {
263 | var entries = this.entries.sort(Entry.sort)
264 |
265 | fs.readFile(path.join(__dirname, '/../assets/DSStore-clean'), function (err, buf) {
266 | if (err) return cb(err)
267 |
268 | var modified = new Buffer(3840)
269 |
270 | modified.fill(0)
271 |
272 | var currentPos = 0
273 |
274 | var P = 0
275 | var count = entries.length
276 |
277 | modified.writeUInt32BE(P, currentPos)
278 | modified.writeUInt32BE(count, currentPos + 4)
279 | currentPos += 8
280 |
281 | entries.forEach(function (e, i) {
282 | var b = e.buffer
283 | b.copy(modified, currentPos)
284 | currentPos += b.length
285 | })
286 |
287 | buf.writeUInt32BE(entries.length, 76)
288 | modified.copy(buf, 4100)
289 |
290 | fs.writeFile(filePath, buf, function (err) {
291 | cb(err)
292 | })
293 | })
294 | }
295 |
296 | module.exports = exports = DSStore
297 |
--------------------------------------------------------------------------------
/lib/entry.js:
--------------------------------------------------------------------------------
1 | var tn1150 = require('tn1150')
2 | var bplist = require('bplist-creator')
3 |
4 | function utf16be (str) {
5 | var b = new Buffer(str, 'ucs2')
6 |
7 | for (var i = 0; i < b.length; i += 2) {
8 | var a = b[i]
9 | b[i] = b[i + 1]
10 | b[i + 1] = a
11 | }
12 |
13 | return b
14 | }
15 |
16 | function Entry (filename, structureId, dataType, blob) {
17 | this.filename = tn1150.normalize(filename)
18 | this.structureId = structureId
19 |
20 | var filenameLength = this.filename.length
21 | var filenameBytes = filenameLength * 2
22 |
23 | this.buffer = new Buffer(4 + filenameBytes + 4 + 4 + blob.length)
24 |
25 | this.buffer.writeUInt32BE(filenameLength, 0)
26 | utf16be(this.filename).copy(this.buffer, 4)
27 | this.buffer.write(structureId, 4 + filenameBytes, 'ascii')
28 | this.buffer.write(dataType, 8 + filenameBytes, 'ascii')
29 |
30 | blob.copy(this.buffer, 12 + filenameBytes)
31 | }
32 |
33 | Entry.prototype.length = function () {
34 | return this.buffer.length()
35 | }
36 |
37 | Entry.sort = function (a, b) {
38 | var s1 = tn1150.compare(a.filename, b.filename)
39 | var s2 = a.structureId.localeCompare(b.structureId)
40 | return s1 || s2
41 | }
42 |
43 | Entry.construct = function (filename, structureId, opts) {
44 | var dataType, blob
45 |
46 | var opt = function (key, def) {
47 | if (key in opts) {
48 | return opts[key]
49 | } else if (def === undefined) {
50 | throw new TypeError('Missing option: ' + key)
51 | } else {
52 | return def
53 | }
54 | }
55 |
56 | switch (structureId) {
57 | case 'BKGD':
58 |
59 | dataType = 'blob'
60 | blob = new Buffer(12 + 4)
61 | blob.writeUInt32BE(blob.length - 4, 0)
62 |
63 | if (opts.color) {
64 | blob.write('ClrB', 4, 'ascii')
65 | throw new Error('Not implemented')
66 | } else if (opts.pictureByteLength) {
67 | blob.write('PctB', 4, 'ascii')
68 | blob.writeUInt32BE(opts.pictureByteLength, 8)
69 | } else {
70 | blob.write('DefB', 4, 'ascii')
71 | }
72 |
73 | break
74 | case 'Iloc':
75 |
76 | dataType = 'blob'
77 | blob = new Buffer(16 + 4)
78 | blob.writeUInt32BE(blob.length - 4, 0)
79 |
80 | blob.writeUInt32BE(opts.x, 4)
81 | blob.writeUInt32BE(opts.y, 8)
82 |
83 | blob.write('FFFFFF00', 12, 'hex')
84 |
85 | break
86 | case 'fwi0':
87 |
88 | throw new Error('Deprecated: Use `bwsp` (I think this is for old OS X)')
89 |
90 | // dataType = 'blob'
91 | // blob = new Buffer(16 + 4)
92 | // blob.writeUInt32BE(blob.length - 4, 0)
93 | //
94 | // blob.writeUInt16BE(opts.top, 4)
95 | // blob.writeUInt16BE(opts.left, 6)
96 | // blob.writeUInt16BE(opts.bottom, 8)
97 | // blob.writeUInt16BE(opts.right, 10)
98 | //
99 | // blob.write(opts.view || 'icnv', 12, 'ascii')
100 | // blob.write('00000000', 16, 'hex')
101 | //
102 | // break
103 | case 'pict':
104 |
105 | // Create an alias with `opts.picturePath`
106 |
107 | throw new Error('Not implemented')
108 |
109 | // break
110 | case 'bwsp':
111 |
112 | dataType = 'bplist'
113 | blob = bplist({
114 | ContainerShowSidebar: true,
115 | ShowPathbar: false,
116 | ShowSidebar: true,
117 | ShowStatusBar: false,
118 | ShowTabView: false,
119 | ShowToolbar: false,
120 | SidebarWidth: 0,
121 | WindowBounds:
122 | '{{' + opt('x') + ', ' + opt('y') + '},' +
123 | ' {' + opt('width') + ', ' + opt('height') + '}}'
124 | })
125 |
126 | break
127 | case 'icvp':
128 |
129 | var plistObj = {
130 | backgroundType: 1,
131 | backgroundColorRed: new bplist.Real(1),
132 | backgroundColorGreen: new bplist.Real(1),
133 | backgroundColorBlue: new bplist.Real(1),
134 | showIconPreview: true,
135 | showItemInfo: false,
136 | textSize: new bplist.Real(12),
137 | iconSize: new bplist.Real(opt('iconSize')),
138 | viewOptionsVersion: 1,
139 | gridSpacing: new bplist.Real(100),
140 | gridOffsetX: new bplist.Real(0),
141 | gridOffsetY: new bplist.Real(0),
142 | labelOnBottom: true,
143 | arrangeBy: 'none'
144 | }
145 |
146 | if (opts.colorComponents) {
147 | plistObj.backgroundColorRed = new bplist.Real(opts.colorComponents[0])
148 | plistObj.backgroundColorGreen = new bplist.Real(opts.colorComponents[1])
149 | plistObj.backgroundColorBlue = new bplist.Real(opts.colorComponents[2])
150 | }
151 |
152 | if (opts.rawAlias) {
153 | plistObj.backgroundType = 2
154 | plistObj.backgroundImageAlias = opts.rawAlias
155 | }
156 |
157 | dataType = 'bplist'
158 | blob = bplist(plistObj)
159 |
160 | break
161 | case 'vSrn':
162 |
163 | dataType = 'long'
164 | blob = new Buffer(4)
165 |
166 | blob.writeUInt32BE(opt('value'), 0)
167 |
168 | break
169 | default:
170 | throw new Error('Not implemented')
171 | }
172 |
173 | if (dataType === 'bplist') {
174 | dataType = 'blob'
175 | var buf = blob
176 |
177 | blob = new Buffer(buf.length + 4)
178 | blob.writeUInt32BE(buf.length, 0)
179 | buf.copy(blob, 4)
180 | }
181 |
182 | return new Entry(filename, structureId, dataType, blob)
183 | }
184 |
185 | module.exports = exports = Entry
186 |
--------------------------------------------------------------------------------
/lib/partition.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 |
3 | exports.sizes = function (max, sizes) {
4 | assert(Array.isArray(sizes))
5 |
6 | var sum = sizes.reduce(function (p, c) {
7 | return p + c
8 | }, 0)
9 |
10 | assert(sum > max)
11 |
12 | var ejecta = []
13 | var bcount = Math.ceil(sum, max)
14 | var target = sum / bcount
15 |
16 | while (true) {
17 | var n = 0
18 | var bsum = 0
19 |
20 | while (n < sizes.length && bsum < target && (bsum + sizes[n]) < max) {
21 | bsum += sizes[n]
22 | n += 1
23 | }
24 |
25 | if (n >= sizes.length) {
26 | break
27 | }
28 |
29 | ejecta.push(n)
30 | n += 1
31 | }
32 |
33 | return ejecta
34 | }
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ds-store",
3 | "version": "0.1.6",
4 | "license": "MIT",
5 | "main": "index.js",
6 | "author": "Linus Unnebäck ",
7 | "scripts": {
8 | "test": "standard"
9 | },
10 | "dependencies": {
11 | "bplist-creator": "~0.0.3",
12 | "macos-alias": "~0.2.5",
13 | "tn1150": "^0.1.0"
14 | },
15 | "contributors": [
16 | "Linus Unnebäck ",
17 | "Davide Liessi "
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "http://github.com/LinusU/node-ds-store.git"
22 | },
23 | "devDependencies": {
24 | "standard": "^7.0.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------